Консультация № 175960
10.01.2010, 00:00
33.70 руб.
0 11 1
Здравствуйте, эксперты! Прошу Вас составить алгоритм для реализации на C++. Задание:
Найти для данного графа ответы на следующие вопросы:
a) является ли граф связанным
b) найдите реберную связность – наименьшее кол-во ребер, удаление которых приводит к несвязному или тривиальному графу.

Граф задается матрицей инцидентности, данную матрицу прилагаю для связного графа.

Заранее благодарю!


Приложение:
//матрица инцидентности
// ребра 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 вершины
int graph[13][20]= {1,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0
0,1,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //1
0,0,1,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //2
0,0,0,1,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //3
0,0,0,0,1,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //4
1,0,0,0,0,1,0,0,1,1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //5
0,1,0,0,0,0,1,0,0,0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, //6
0,0,1,0,0,0,0,1,0,0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, //7
0,0,0,1,0,0,0,0,0,0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, //8
0,0,0,0,1,0,0,0,0,0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, //9
0,0,0,0,0,1,0,0,0,0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, //10
0,0,0,0,0,0,1,0,0,1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, //11
0,0,0,0,0,0,0,1,1,0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}; //12

Обсуждение

давно
Профессор
230118
3054
11.01.2010, 03:50
общий
Yulesik:
Почему именно матрицу инцидентности, матрицей смежности было бы легче.
давно
Профессор
230118
3054
11.01.2010, 03:54
общий
Yulesik:
Идея может быть рекурсивная. 1 точка - это связный граф. Пусть мы имеем связный граф из N-1 точек. Тогда при добавлении еще одной точки граф связный, если эта точка непосредственно связана хотя бы с одной точкой графа из N-1 точек. Начинаем с 1-ой вершины. На первом шаге добавляем все связанные с ней вершины. На втором - связанные с вершинами, добавленными на предыдущем этапе. Если в какой-то момент добавить нельзя, а вершины не кончились, граф не связный. Если добавлены все точки, граф связный.
Неизвестный
11.01.2010, 15:47
общий
Гаряка Асмик:
А вы язык пролог знаете? просто у меня есть реализация этой задачи на прологе, но там есть какая то неточность для проверки на реберную связность. Он выдает ни минимальное количество ребер, а что там исправить ума ни приложу.
давно
Профессор
230118
3054
11.01.2010, 16:26
общий
Yulesik:
Пролог относится к другому типу языков. Программу с него на С перевести очень трудно. Предлагаю алгоритм, который убьет сразу двух зайцев. Перебираем ребра(столбцы матрицы инц-сти). Создаем вспомогательный вектор для вершин. Вначале все значения равны 0. Первое ребро связывает 2 вершины. Этим вершинам в векторе пишем 1. Берем следующее ребро. Если в нем участвует вершина, у которой в векторе не 0, обоим вершинам записываем это число. Иначе первое свободное число. Если в ребре участвуют 2 вершины с разными числами, большему присваиваем меньшее. Как только в векторе все числа стали одинаковые -1, граф стал связным. Число связности - количество неперебранных еще ребер. Если ребра кончились, а в векторе разные числа, значит граф несвязный. Причем вершины с одинаковыми числами связаны друг с другом.
Неизвестный
12.01.2010, 13:13
общий
Yulesik:
Добрый день! А исходник на Прологе скинуть можете?
давно
Старший Модератор
17042
808
14.01.2010, 04:19
общий
Гаряка Асмик:
Возьмётесь за решение этой задачи?
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
Неизвестный
14.01.2010, 20:00
общий
Задача сделана. Вот исходник на прологе:
Код:
% Граф задается списком ребер и вершин

test:-minset([1,2,3,4,5],[[1,2],[2,3],[3,4],[4,5],[5,1],[5,2]], Min), write(Min).

minset(V,E, Min):-
get_edge_set(E, Min), % Порождение множества удаляемых ребер.
not(is_connected_without(V,E, Min)). % Проверка того что граф становится реберно несвязным при удалении ребер из порожденного множества.


connected(V, E):-
not(disconnected(V, E)).
disconnected(V, E):-
member(V1, V),
member(V2, V),
not(eq(V1, V2)),
not(path(V1, V2, E,[])).


% Минимальность такого множества обеспечивается построением - сначала порождаются все варианты из одного ребра, потом из двух и т.д.
% Фактически - это построение всех подмножеств данного множества, начиная с мощности = 1 и по возрастанию

get_edge_set(E, Edges):-
len(Len, E), % Определение мощности множества (длина списка ребер)
int(N), % Счетчик мощности.
N < Len,
subset(N, E, Edges). % Все подмножества множества заданной мощности

% Определение мощности множества
len(0,[]).
len(NewN, [Head| Tail]):-
len(N,Tail),
NewN is N + 1.

%Счетчик мощности
int(1).
int(N):-int(M), N is M + 1.

% Все подмножества множества заданной мощности
subset(0, _, []):- !.
subset(N, E, [Edge | Rest]):-
members(Edge, E, NewGraph),
NewN is N - 1,
subset(NewN, NewGraph, Rest).


% Предикат принадлежности элемента множеству и возвращения множества без этого элемента и всех ему предшествующих.
members(Element, [Element | Tail], Tail).
members(Element, [Head | Tail], Tail2):-
members(Element, Tail, Tail2).

% Проверка нового графа на реберную связность.
is_connected_without(V,E, Min):-
minus_set(E, Min, NewGraph), % Вычитание множеств - получение нового графа.
connected(V, NewGraph).

connected(V, E):-
not(disconnected(V, E)).
disconnected(V, E):-
member(V1, V),
member(V2, V),
not(eq(V1, V2)),
not(path(V1, V2, E,[])).

% Вычитание множеств.
minus_set([ ], _, [ ]).
minus_set([Head | Tail], Set2, Set):-
member(Head, Set2), !,
minus_set(Tail, Set2, Set).
minus_set([Head | Tail], Set2, [Head | Set]):-
minus_set(Tail, Set2, Set).



path(St, End, E, _):-
edge(St, End, E).
path(St, End, E, Passed):-
edge(St, Via, E),
not(member([St, Via], Passed)),
path(Via, End, E, [[St, Via] | Passed]).

edge(St, End, E):-
member([St, End], E).
edge(St, End, E):-
member([End, St], E).
eq(V, V).

member(E, [E | _]).
member(E, [_ | T]):-
member(E, T).



давно
Старший Модератор
17042
808
14.01.2010, 22:40
общий
lamed:
Исходный текст на прологе готов. Возьмётесь за перевод?
Об авторе:
We have but faith: we cannot know;
For knowledge is of things we see;
And yet we trust it comes from thee,
A beam in darkness: let it grow.
-----
https://www.linkedin.com/in/andreynkuznetsov
https://www.researchgate.net/profile/Andrey_Kuznetsov11
http://www.researcherid.com/rid/K-8824-2014
Неизвестный
20.01.2010, 22:10
общий
Dr_Andrew:
Добрый вечер! Выкладываю код (ответ на первый вопрос, CodeBlocks/G++) в мини-форуме. Надеюсь, коллеги обнаружат "ляпы".
Идея связности, как я ее понял, состоит в том, что из любой вершины графа можно попасть в любую другую, то есть все вершины связного графа можно отнести к одному множеству, а вершины несвязного графа относятся, как минимум к двум неперсекающимся множествам (то есть нет никакой неупорядоченной пары, в которой одним элементом была бы вершина первого множества, а вторым элементам - вершина другого множества).
Формируем вспомогательный список ребер (пар). Создаем множество вершин как множество, состоящее из элементов первой пары. Затем "крутим" список ребер, если один из элементов пары входит в множество вершин, таки добавляем в множество вершин по очереди каждый из элементов, затем удаляем из списка. Если операция состоялась, "крутим" дальше. После завершения смотрим, не пустой ли список пар. Дополнительно проверяем, а все ли вершины включены. /* Возможно, эту проверку требуется перенести в начало программы */
Код:

/*
В примере неявно подразумевается неориентированный граф.
Предварительные определения.
1. Маршрутом в графе называется чередующаяся последовательность вершин и ребер,
в которой любые два соседних элемента инцидентны
v0, e1, v1, e2, ..., ek, uk
2. Если все ребра различны, то маршрут называется цепью.
3. Если все вершины (а, значит, и ребра) различны, то маршрут называется простой цепью
4. Если есть цепь, соединяющая вершины v0 и e0, то есть и простая цепь,
соединяющая эти вершины.
5. Две вершины графа называются связными, если существует соединяющая их простая цепь.
6. Граф является связным, если каждые две вершины его связные.
/* Галушкина Ю.И. Конспект лекций по дискретной математике - М.:Айрис-пресс, 2007 */


/*
Построим множество связных вершин и выясним, не остались ли какие-то вершины,
не попавшие в это множество; если таковых нет граф связный,
в противном случае - граф несвязный

1. Из матрицы инцидентности получаем список ребер lines
2. Берем одно ребро (пару вершин). Они образуют множество связных вершин nodes.
3. Просматриваем в цикле все оставшиеся пары.
Если хотя бы одна из вершин пары встречается в nodes, добавляем в nodes и вторую вершину,
точнее сказать, if (v1 in nodes) or (v2 in nodes) then nodes := nodes + {v1} + {v2};
Удаляем пару из списка.
Цикл завершается, если список ребер пуст либо на последнем шаге не было изменений списка
4. Проверим, все ли вершины есть в множестве nodes
5. Проверим, не осталось ли ребер в списке.
*/

#include <iostream>
#include <list>
#include <set>
using namespace std;

struct CLine // ребро
{
int node1;
int node2;
};

int main()
{
const int rows=13;
const int cols=20;
int graph[rows][cols]=
{
{1,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //0
{0,1,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //1
{0,0,1,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //2
{0,0,0,1,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //3
{0,0,0,0,1,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //4
{1,0,0,0,0,1,0,0,1,1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //5
{0,1,0,0,0,0,1,0,0,0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, //6
{0,0,1,0,0,0,0,1,0,0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0}, //7
{0,0,0,1,0,0,0,0,0,0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0}, //8
{0,0,0,0,1,0,0,0,0,0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1}, //9
{0,0,0,0,0,1,0,0,0,0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, //10
{0,0,0,0,0,0,1,0,0,1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, //11
{0,0,0,0,0,0,0,1,1,0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1} //12
};
// все ли вершины указаны в матрице?
bool node_checked=true;
for (int i=0; i<rows && node_checked; i++)
{
node_checked = false; // вершина не проверена
for (int j=0;j<cols;j++)
{
if (graph[i][j])
{
node_checked=true; // вершина проверенаs
break;
}
}
}
if (!node_checked)
{
cout << "Граф несвязный" << endl;
return 0;
}

CLine line;
list<CLine>lines; // список ребер
for (int j=0; j<cols; j++)
{
int count=0;
line.node1=-1; // вспомогательная пара
line.node2=-1;
for (int i=0; i<rows; i++)
{
if (graph[i][j]==1)
{
if (count==0)
line.node1=i;
else if (count==1)
line.node2=i;
else
{
cout << "Неверное заполнение матрицы инцидентности!" << endl;
return 1;
}
count++;
}
}
if (line.node1!=-1 && line.node2!=-1)
lines.push_back(line);
}
if (lines.empty())
{
cout << "Неверное заполнение матрицы инцидентности!" << endl;
return 1;
}

set<int> nodes; // множество связных вершин
list<CLine>::iterator iter=lines.begin();
nodes.insert(iter->node1);
nodes.insert(iter->node2);

bool changed = true; // было изменение на последнем шаге?
unsigned i1, i2;
while (!(lines.empty()) && changed)
{
changed = false;
// в начале очередного просмотра списка ребер считаем, что
// изменения на последнем шаге не было
iter = lines.begin();
while (iter!=lines.end())
{
list<CLine>::iterator thisone=iter;
iter++;
if (nodes.find(thisone->node1)!=nodes.end() ||
nodes.find(thisone->node2)!=nodes.end())
// if (node1 in nodes) or (node2 in nodes)
{
// nodes = nodes + {node1} + {node2}
nodes.insert(thisone->node1);
nodes.insert(thisone->node2);
lines.erase(thisone);
changed = true;
}
}
}

if (lines.empty())
{
cout << "Граф связный" << endl;
}
else
{
cout << "Граф несвязный" << endl;
cout << "Не обработаны ребра" << endl;
for (iter=lines.begin(); iter!=lines.end(); iter++)
{
cout << (*iter).node1 << ";" << (*iter).node2 << endl;
}
}
system("Pause");

return 0;
}

давно
Академик
320937
2216
24.01.2010, 17:42
общий
это ответ
Здравствуйте, Yulesik. Ответ на первый вопрос в приложении, CodeBlocks/G++.



Приложение:
/*
В примере неявно подразумевается неориентированный граф.
Предварительные определения.
1. Маршрутом в графе называется чередующаяся последовательность вершин и ребер,
в которой любые два соседних элемента инцидентны
v0, e1, v1, e2, ..., ek, uk
2. Если все ребра различны, то маршрут называется цепью.
3. Если все вершины (а, значит, и ребра) различны, то маршрут называется простой цепью
4. Если есть цепь, соединяющая вершины v0 и e0, то есть и простая цепь,
соединяющая эти вершины.
5. Две вершины графа называются связными, если существует соединяющая их простая цепь.
6. Граф является связным, если каждые две вершины его связные.
/* Галушкина Ю.И. Конспект лекций по дискретной математике - М.:Айрис-пресс, 2007 */


/*
Построим множество связных вершин и выясним, не остались ли какие-то вершины,
не попавшие в это множество; если таковых нет граф связный,
в противном случае - граф несвязный

1. Из матрицы инцидентности получаем список ребер lines
2. Берем одно ребро (пару вершин). Они образуют множество связных вершин nodes.
3. Просматриваем в цикле все оставшиеся пары.
Если хотя бы одна из вершин пары встречается в nodes, добавляем в nodes и вторую вершину,
точнее сказать, if (v1 in nodes) or (v2 in nodes) then nodes := nodes + {v1} + {v2};
Удаляем пару из списка.
Цикл завершается, если список ребер пуст либо на последнем шаге не было изменений списка
4. Проверим, все ли вершины есть в множестве nodes
5. Проверим, не осталось ли ребер в списке.
*/

#include <iostream>
#include <list>
#include <set>
using namespace std;

struct CLine // ребро
{
int node1;
int node2;
};

int main()
{
const int rows=13;
const int cols=20;
int graph[rows][cols]=
{
{1,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //0
{0,1,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //1
{0,0,1,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //2
{0,0,0,1,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //3
{0,0,0,0,1,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //4
{1,0,0,0,0,1,0,0,1,1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //5
{0,1,0,0,0,0,1,0,0,0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, //6
{0,0,1,0,0,0,0,1,0,0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0}, //7
{0,0,0,1,0,0,0,0,0,0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0}, //8
{0,0,0,0,1,0,0,0,0,0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1}, //9
{0,0,0,0,0,1,0,0,0,0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, //10
{0,0,0,0,0,0,1,0,0,1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, //11
{0,0,0,0,0,0,0,1,1,0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1} //12
};
// все ли вершины указаны в матрице?
bool node_checked=true;
for (int i=0; i<rows && node_checked; i++)
{
node_checked = false; // вершина не проверена
for (int j=0;j<cols;j++)
{
if (graph[i][j])
{
node_checked=true; // вершина проверенаs
break;
}
}
}
if (!node_checked)
{
cout << "Граф несвязный" << endl;
return 0;
}

CLine line;
list<CLine>lines; // список ребер
for (int j=0; j<cols; j++)
{
int count=0;
line.node1=-1; // вспомогательная пара
line.node2=-1;
for (int i=0; i<rows; i++)
{
if (graph[i][j]==1)
{
if (count==0)
line.node1=i;
else if (count==1)
line.node2=i;
else
{
cout << "Неверное заполнение матрицы инцидентности!" << endl;
return 1;
}
count++;
}
}
if (line.node1!=-1 && line.node2!=-1)
lines.push_back(line);
}
if (lines.empty())
{
cout << "Неверное заполнение матрицы инцидентности!" << endl;
return 1;
}

set<int> nodes; // множество связных вершин
list<CLine>::iterator iter=lines.begin();
nodes.insert(iter->node1);
nodes.insert(iter->node2);

bool changed = true; // было изменение на последнем шаге?
unsigned i1, i2;
while (!(lines.empty()) && changed)
{
changed = false;
// в начале очередного просмотра списка ребер считаем, что
// изменения на последнем шаге не было
iter = lines.begin();
while (iter!=lines.end())
{
list<CLine>::iterator thisone=iter;
iter++;
if (nodes.find(thisone->node1)!=nodes.end() ||
nodes.find(thisone->node2)!=nodes.end())
// if (node1 in nodes) or (node2 in nodes)
{
// nodes = nodes + {node1} + {node2}
nodes.insert(thisone->node1);
nodes.insert(thisone->node2);
lines.erase(thisone);
changed = true;
}
}
}

if (lines.empty())
{
cout << "Граф связный" << endl;
}
else
{
cout << "Граф несвязный" << endl;
cout << "Не обработаны ребра" << endl;
for (iter=lines.begin(); iter!=lines.end(); iter++)
{
cout << (*iter).node1 << ";" << (*iter).node2 << endl;
}
}
system("Pause");

return 0;
}
Неизвестный
24.01.2010, 17:46
общий
Yulesik:
Добрый день! Обращаю Ваше внимание на то, что обнаружил в мини-форуме "пенку", /* и поправил ее */, актуальный исходник дан в ответе. С уважением.
Форма ответа