Помощь - Поиск - Пользователи - Календарь
Полная версия: Графы. Фундаментальная система циклов связного графа
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Юлия92
Написала программу по псевдокоду...Но результат работы процедур не выдается....Не пойму в чем проблема...Пседокод прилагаю..заранее благодарю за помощь))

uses crt;
const
max=50;
type
TMatrix = array [1..max,1..max] of byte;
TArray = array [1..max] of integer;

var
i,j,m,k,z : integer;
num,ftr,masQ: TArray;
Matrix : TMatrix; {матрица смежности}
n ,nz: integer; {количество вершин графа}

procedure save(i,j,nz:integer);
begin
z:=i;
while z<>j do
begin
masQ[nz]:=z;
z:=ftr[z];
masQ[nz]:=j;
masq[nz]:=i;
end;
end;
procedure cicle(i:integer);
var
j:integer;

begin
k:=k+1;
num[i]:=k;
for j:=1 to n do
begin
if (Matrix[i, j]<>0) and (num[j]=0) then
begin
ftr[j]:=i;
cicle(j);
end
else if ftr[i]<>j then
begin
nz:=nz+1;
save(i,j,nz);
end;
end;
end;

begin
clrscr;

writeln('=======Фундаментальная система циклов связного графа====');

write('Введите количество вершин графа:');
readln(n);
writeln('Заполнение матрицы смежности');
for i:=1 to n do
for j:=1 to n do
begin
Write('(',i,',',j,')=');
read(Matrix[i,j]);
if Matrix[i,j] <> 0 then Matrix[i,j]:=1;
end;
{$endif}
//вывод матрицы смежностиж;
writeln('Матрица смежности');
for i:=1 to n do
begin
for j:=1 to n do
write(Matrix[i,j],' ');
writeln;
end;
writeln;


writeln('Результат :');
n:=0; m:=0;
for i:=1 to n do
begin
num[i]:=0; {ни одна вершина не посещалась}
ftr[i]:=0;
n:=n+1;
m:=m+(n*n);
m:= round(m / 2);
k:=1;
end;
for i:=1 to m-n+1 do
begin
masQ[i]:=0;
k:=0;
nz:=0;
cicle(i);

//вывод массивов num ftr;
write('num: ');
for i:=1 to n do
write(num[i]:3);
writeln;
write('ftr: ');
for i:=1 to n do
write(ftr[i]:3);
writeln;
write('masQ: ');
for i:=1 to n do
write(masQ[i]:3);
writeln;
write('nz: ');
write(nz);
writeln;
readln;
end;
end.

Нажмите для просмотра прикрепленного файла
Федосеев Павел
1. Обрати внимание, что в этой задаче граф предлагается задавать не матрицей смежности, а списками смежности. Соответственно при инициализации в цикле m:=m+n*n; - совсем ахинея, не считая ввода матрицы смежностей. Хотя подойдёт и матрица, но в методичке предлагается научиться работать со списками.
2. Кроме того, masQ - это не массив чисел, а массив стеков. И в процедуре SAVE операция masQ[nZ]<=i означает занесение числа i в вершину стека (стека под номером nZ в массиве стеков masQ), а не примитивное присвоение. Соответственно и вывод на экран из стека и массива стеков будет иным.
3. В SAVE строка с номером 5 вне тела цикла.

Внимательно прочти теорию.

Нечестно манипулировать форумчанами выдавая механический перевод псевдокода за попытку разобраться в теме. Хотя несомненно много лучше постановки задачи с последующим "разрешением" сделать всё "под ключ".

Предвидя вопрос о стеке...
Стек можно реализовать в виде массива [0..max]. В [0] элементе будет храниться глубина стека, а начиная с 1-го элемента будет располагаться сам стек. Соответственно, массив стеков становится двумерным массивом. Занесение в стек номер nZ числа i будет
Inc(masQ[nZ][0]);
x:=masQ[nZ][0];
masQ[nZ][x]:=i;

И лучше всего эти строки оформить процедурой.

Или же стек можно реализовать в виде динамической структуры.
Юлия92
спасибо большое за помощь,просто мне преподаватель дал книгу эту и сказала следовать тупо коду,а на деле оказалось не все так просто
Федосеев Павел
Если непонятно - задавай вопросы. Конечно, если возможно - преподавателю, он увидит твою работу. Если в методичке слишком заумно, задай поиск в сети.
вот ссылки навскидку
"http://rain.ifmo.ru/cat/view.php/theory/graph-circuits-cuts/euler-2004",
"http://www.intuit.ru/department/algorithms/gaa/7/3.html"
Юлия92
Если быть честной непонятно мне вообще в процедуре Save c 3-5 строчку как оформить это...
Федосеев Павел
Я вижу так:
procedure Save(i, j, nZ : integer);
var
z : integer;
begin
z:=i; {1}
while (z<>j) and (z<>0) do {2}
begin
StackPush(masQ[nZ], z); {3}
z:=ftr[z]; {4}
end;
StackPush(masQ[nZ], j); {5}
StackPush(masQ[nZ], i); {5}
end;

Массив стеков я организовал по-детски - по принципу массива строк String. Каждый стек это массив, у которого в элементе с индексом [0] находится глубина стека (его длина):
type
{TStack - тип для хранения стека фундаментальных циклов.
Его размер равен цикломатическому числу связанного графа,
т.е. m-n+1 или в максимальном виде (max*max-max+1)
}
TListX = array [0..max] of integer;
TStack = array [1..max*max-max+1] of TListX;
var
masQ : TStack; {массив стеков}

{помещение элемента Elem в стек Stack}
procedure StackPush( var Stack : TListX; Elem : Byte);
var
i : integer;
begin
i:=Stack[0];
inc(i);
Stack[i]:=Elem;
Stack[0]:=i;
end;

Это не самый лучший способ, но для упрощения реализации сойдёт.
Юлия92
спасибо за помощь...как отблагодарить не знаю... smile.gif
Федосеев Павел
Недорого - 3 месяца активной помощи (ответов) страждущим на форуме (по согласованию с администрацией можно и без кандалов) или старушку через дорогу перевести lol.gif
Юлия92
Ой этим я и так занимаюсь....помогаю бедным и обездоленным.... rolleyes.gif
Юлия92
 
uses crt;
const
max=50;

type
TMatrix = array [1..max,1..max] of byte;
TArray = array [1..max] of integer;
TList = array[0..max]of integer;
Tstack = array[1..max*max-max+1]of TList;
var
i,j,m,k,z : integer;
num,ftr : TArray;
Matrix : TMatrix; {матрица смежности}
n ,nz : integer; {количество вершин графа}
masQ:TStack;

procedure StackPush(Stack:TList;Elem:byte);
var
i:integer;
begin
i:=Stack[0];
inc(i);
Stack[i]:=Elem;
Stack[0]:=i;
end;
procedure save(i,j,nz:integer);
var
z:integer;
begin
z:=i;
while (z<>j) and (z<>0) do
begin
StackPush(masQ[nz],z);
z:=ftr[z];
end;
StackPush(masQ[nz],j);
StackPush(masq[nz],i)
end;
procedure cicle(i:integer);
var
j:integer;

begin
k:=k+1;
num[i]:=k;

for j:=1 to n do
begin
if (Matrix[i, j]<>0) and (num[j]=0) then
begin
ftr[j]:=i;
cicle(j);
end
else if ftr[i]<>j then
begin
nz:=nz+1;
save(i,j,nz);
end;
end;
end;

begin
clrscr;

writeln('=======Фундаментальная система циклов связного графа====');

write('Введите количество вершин графа:');
readln(n);
writeln('Заполнение матрицы смежности');
for i:=1 to n do
for j:=1 to n do
begin
Write('(',i,',',j,')=');
read(Matrix[i,j]);
if Matrix[i,j] <> 0 then Matrix[i,j]:=1;
end;
{$endif}
//вывод матрицы смежностиж;
writeln('Матрица смежности');
for i:=1 to n do
begin
for j:=1 to n do
write(Matrix[i,j],' ');
writeln;
end;
writeln;

//процедура dfs;
writeln('Результат dfs');
n:=0; m:=0;
for i:=1 to n do
begin
num[i]:=0; {ни одна вершина не посещалась}
ftr[i]:=0;
n:=n+1;
m:=m+(n*n);
m:= m div 2;
k:=1;
end;
for i:=1 to m-n+1 do
begin
StackPush(masQ[i],0);
k:=0;
nz:=0;
cicle(i);


write('num: ');
for i:=1 to n do
write(num[i]:3);
writeln;
write('ftr: ');
for i:=1 to n do
write(ftr[i]:3);
writeln;
write('masQ: ');

writeln;
write('nz: ');
write(nz);
writeln;
readln;
end;
end.

Прошу прощения за мою тупость ...но есть проблема теперь и с выводом результата,хотя ошибок в процедурах вроде нет
Федосеев Павел
masQ? Он представляет из себя массив от 1 до nZ - первый (внешний цикл от 1 до nZ), каждый стек представляет из себя массив переменной длины, в котором элемент с нулевым индексом содержит длину стека (внутренний цикл от 1 до masQ[i][0]):
  writeln('nZ:  ', nZ);
writeln('masQ: ');
for i:=1 to nZ do
begin
write(i, '. ');
for j:=1 to masQ[i][0] do
write(masQ[i][j]:3);
writeln;
end;


А можно замечания к коду?
- переменная n вводится, а чуть ниже ей присваивается 0.
- переменной m присваивается не то значение. смотри внимательно псевдокод
- стек странно инициализируется. достаточно обнулить длины каждого стека for i:=1 to m-n+1 do masQ[i][0]:=0;
- из основной программы cicle вызывается один раз с параметром 1 (см. псевдокод)
Это из того, что бросается в глаза.

Далее, когда я попытался несколько дней назад отладить собственный вариант псевдокода, по ходу выполнения программы возникали исключения вида "полез в чужую память". Пришлось дополнить условия в save. Это увидишь отладчиком включив опци проверки диапазонов {$R+, Q+}.

Плюс к этому, в circle формировалась пара-тройка "левых" циклов. Также лечится усложнением условия сохранения вновь найденного цикла.
Юлия92
Павел это снова я с вопросами...))))Почему n потом обнуляется??сначала я ее ввожу для заполнения матрицы смежности....а остальное по псевдокоду...вот с оформлением m я сама не очень уверена....,но в 7 строке...получается что если m-нечетное,то идет присваение целому ,десятичного числа..А так оно все работает запускается,но процедуры не выводят никаких результатов,а теория никак не помогает((((

uses crt;
const
max=50;
type
TMatrix = array [1..max,1..max] of byte;
TArray = array [1..max] of integer;
TList = array[0..max]of integer;
Tstack = array[1..max*max-max+1]of TList;
var
i,j,m,k,z : integer;
num,ftr : TArray;
Matrix : TMatrix; {матрица смежности}
n ,nz : integer; {количество вершин графа}
masQ:TStack;
procedure StackPush(Stack:TList;Elem:byte);
var
i:integer;
begin
i:=Stack[0];
inc(i);
Stack[i]:=Elem;
Stack[0]:=i;
end;
procedure Save(i, j, nZ : integer);
var
z : integer;
begin
z:=i;
while (z<>j) and (z<>0) do
begin
StackPush(masQ[nZ], z);
z:=ftr[z];
end;
StackPush(masQ[nZ], j);
StackPush(masQ[nZ], i);
end;
procedure cicle(i:integer);
var
j:integer;

begin
k:=k+1;
num[i]:=k;
for j:=1 to n do
begin
if (Matrix[i, j]<>0) and (num[j]=0) then
begin
ftr[j]:=i;
cicle(j);
end
else if ftr[i]<>j then
begin
nz:=nz+1;
save(i,j,nz);
end;
end;
end;

begin
clrscr;

writeln('=======Фундаментальная система циклов связного графа====');

write('Введите количество вершин графа:');
readln(n);
writeln('Заполнение матрицы смежности');
for i:=1 to n do
for j:=1 to n do
begin
Write('(',i,',',j,')=');
read(Matrix[i,j]);
if Matrix[i,j] <> 0 then Matrix[i,j]:=1;
end;
{$endif}
//вывод матрицы смежностиж;
writeln('Матрица смежности');
for i:=1 to n do
begin
for j:=1 to n do
write(Matrix[i,j],' ');
writeln;
end;
writeln;

//процедура dfs;
writeln('Результат dfs');
n:=0; m:=0;
for i:=1 to n do
begin
num[i]:=0; {ни одна вершина не посещалась}
ftr[i]:=0;
n:=n+1;
m:=m+(n*n);
end;
m:= m div 2;


for i:=1 to m-n+1 do
begin
masQ[i][0]:=0;
k:=0;
nz:=0;
cicle(1);
end;

//вывод массивов num ftr;
write('num: ');
for i:=1 to n do
write(num[i]:3);
writeln;
write('ftr: ');
for i:=1 to n do
write(ftr[i]:3);
writeln;
writeln('nZ: ', nZ);
writeln('masQ: ');
for i:=1 to nZ do
begin
write(i, '. ');
for j:=1 to masQ[i][0] do
write(masQ[i][j]:3);
writeln;
end;
end.
Федосеев Павел
Юль, ты делаешь все механически, не вникая.
Мне проще отдать тебе готовый код, чем объяснять.

В архиве две папки. В одной работающий код по псевдокоду, с учётом примечания, найденного в книге Окулова о том, что к сохранению цикла переходим не только когда j вершина не предыдущая для i, но и когда при построении дерева поиска в глубину i вершина встретилась после j (т.е. найдено обратное ребро - ведущее вверх).
Цитата
Поиск в глубину является естественным подходом, используемым для нахождения фундаментальных циклов. Строится каркас, а каждое обратное ребро порождает цикл относительно этого каркаса. Для вывода циклов необходимо хранить порядок обхода графа при поиске в глубину (номера вершин) — массив St, а для определения обратных ребер вершины следует «метить» (массив Gnum) в той очередности, в которой они просматриваются. Если для ребра <v,j> оказывается, что значение метки вершины с номером j меньше, чем значение метки вершины с номером i, то ребро обратное и найден цикл.


Во второй папке программа с аналогичной функциональностью, встретившаяся мне на одном из форумов. Топикстартер утверждал, что она из книги Иванов Б.Н. "Дискретная математика. Алгоритмы и программы." Она мне просто понравилась.

В обоих случаях я использовал пример из твоей методички. Кстати, в интернете она встречается в pdf и с внесёнными исправленями.
Юлия92
Спасибо тебе большое,но я вникала я перерыла все учебники по этой теме...просто сложно когда препод по практике ничего толком на твои вопросы не отвечает...мне самой легче не тупо сделать а понять,а чтобы понять надо чтобы тебе на примере показали хотя бы что -то...чего у нас нет...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.