Решение задач на графах

Общие сведения об алгоритмах на графах. Кратчайшие расстояния на графах. Задача "Маневры" (Автор - Перепечко С.Н.). Задача "Пирамида Хеопса" (Автор - Котов В.М.). Задача "Эх, дороги" (Автор - Котов В.М.). Задача "Перекрестки" (Автор - Котов В.М.).

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 05.01.2010
Размер файла 59,8 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

...

N+2 строка> <имя функции> <кол-во параметров>[<список имен параметров>]

Выходной файл OUTPUT.TXT

Формат вывода:

Размер памяти (в ячейках)

имя 1-й вычисляемой функции

имя 2-й вычисляемой функции

....

имя функции, которую необходимо вычислить

Примечание: имя функции есть натуральное число от 1 до N.

Пример.

Ввод Вывод

5 Размер памяти: 2 ячейки

1 Порядок:

1 2 2 3 Функция 4

2 0 Функция 5

3 2 4 5 Функция 3

4 0 Функция 2

5 0 Функция 1

В кратком изложении в данной задаче требуется сделать следующее:

- найти S - максимальную степень среди тех вершин, что подлежат обходу (поиск в глубину DFS1)

- необходимая память вычисляется по формуле

MaxS = S + k -1

где S - найдено на предыдущем шаге (DFS1),

а k - максимальное количество вершин одного уровня вложенности с такой же степенью S.

Для вычисления k совершается обход повторным поиском в глубину DFS2

- третьим поиском в глубину DFS3 находим и помещаем в очередь V все вершины, степень которых равна S.

- последним, четвертым поиском в глубину обходим данное дерево в порядке вершин в очереди V. То есть, в первую очередь вычисляем те функции, для которых требуется максимальная память.

Рассмотрим реализацию алгоритма более подробно.

Ввод исходных данных осуществляется следующим образом:

Read (N,FC);

for i:=1 to N do

begin

read(f,kG[f]);

for j:=1 to kG[f] do read(G[f,j]);

end;

Здесь

N - исходное количество вершин,

FC - номер функции, которую нужно вычислить

kG[i] - количество параметров для вычисления функции i

G[i,j] - j-тый параметр, требуемый для вычисления функции i

Тело главной программы выглядит так :

for i:=1 to N do color[i]:=WHITE; {пометить свободными все вершины}

DFS1(FC); {находим S - максимальную степень вершин используемых для вычисления функции FC}

MaxS:=S;

DFS2(FC); {Вычисляем

K - количество вершин со степенью S в текущем слое и

MaxS - максимальная из значений по слоям величина S+K-1}

kv:=0;

DFS3(FC); {Поместить в массив V все вершины, степень которых равна S, количество таких вершин - в переменной kv}

kr:=0;

for i:=1 to kv do DFS4(v[i]); {Обход графа поиском в глубину начиная с вершин с максимальной степенью из массива V.

Найденные вершины заносить в массив r}

writeln(MaxS); {вывод количества ячеек памяти}

for i:=1 to kr do writeln(r[i]); {вывод порядка вычисления функций}

Полное решение задачи приводится ниже

program by95d2t1;

const

WHITE = 1;

GRAY = 2;

BLACK = 3;

var

G : array [1..100,1..100] of longint;

kG,v,color,r : array [1..100] of longint;

N,FC,i,j,s,f,kv,MaxS,kr : longint;

procedure DFS1(u:longint);

var

i,k : longint;

begin

if s<kG[u] then s:=kG[u];

for i:=1 to kG[u] do DFS1(G[u,i]);

end;

procedure DFS2(u:longint);

var

i,k : longint;

begin

k:=0;

for i:=1 to kG[u] do

if kG[G[i,j]]=s then inc(k);

if MaxS<s+k-1 then MaxS:=s+k-1;

for i:=1 to kG[u] do DFS2(G[u,i]);

end;

procedure DFS3(u:longint);

var

i,k : longint;

begin

if kG[u]=s

then

begin

for i:=1 to kG[u] do DFS3(G[u,i]);

nc(kv); v[kv]:=u;

end;

end;

procedure DFS4(u:longint);

var

i : longint;

begin

color[u]:=GRAY;

if kG[u]<>0

then

for i:=1 to kG[u] do

if color[G[u,i]]<>GRAY

then DFS4(G[u,i]);

inc(kr); r[kr]:=u;

end;

begin

assign(input,'input.txt'); reset(input);

assign(output,'output.txt'); rewrite(output);

read(N,FC);

for i:=1 to N do

begin

read(f,kG[f]);

for j:=1 to kG[f] do read(G[f,j]);

end;

for i:=1 to N do color[i]:=WHITE;

DFS1(FC);

MaxS:=s; DFS2(FC);

kv:=0; DFS3(FC);

kr:=0; for i:=1 to kv do DFS4(v[i]);

writeln(MaxS);

for i:=1 to kr do writeln(r[i]);

close(input); close(output);

end.

4. Сильносвязные компоненты и доминантные множества

Подграф графа называется его сильносвязной компонентой, если каждая из вершин подграфа достижима от любой из верши подграфа.

Доминантное множество - это минимальное множество вершин графа, из которого достижимы все вершины графа.

Алгоритмы построения сильносвязных компонент и доминантных множеств графа рассмотрим на примерах.

4.1 Задача "Карточки"

Республиканская олимпиада по информатике 1994г

1. Есть N карточек. На каждой из них черными чернилами написан ее уникальный номер - число от 1 до N. Также на каждой карточке красными чернилами написано еще одно целое число, лежащее в промежутке от 1 до N (некоторыми одинаковыми "красными" числами могут помечаться несколько карточек).

Например, N=5, 5 карточек помечены следующим образом:

---------------

"черное" число ¦ 1¦ 2¦ 3¦ 4¦ 5¦

---------------

"красное" число ¦ 3¦ 3¦ 2¦ 4¦ 2¦

---------------

Необходимо выбрать из данных N карточек максимальное число карточек таким образом, чтобы множества "красных" и "черных" чисел на них совпадали.

Для примера выше это будут карточки с "черными" номерами 2, 3, 4 (множество красных номеров, как и требуется в задаче, то же - {2,3,4}).

ВВОД: <N=> N, N<=50

<"Черный" номер 1, "красный" -> "красное"_число_1

......

<"Черный" номер N, "красный" -> "красное"_число_N

ВЫВОД:

<В выбранном множестве элементов количество элементов> S

<"Черные" номера выбранных карточек> a1, ..., aS

Пример ввода Пример вывода

6 6

1 2 1

2 3 2

3 4 3

4 5 4

5 1 5

6 6 6

Фактически в задаче требуется найти все сильно связные компоненты представляемого карточками ориентированного графа и добавить к ним карточки, на которых и красным и черным цветом написаны одни и те же числа.

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

Тело главной части программы будет выглядеть так:

readln(N); {Читаем количество карточек}

M:=0; {Количество карточек в результате}

for i:=1 to N do {Для всех карточек}

begin

readln(u,v); {Читаем карточку}

inc(kG[u]); G[u,kG[u]]:=v; {Пополняем по ней граф}

if u=v {Если красное число равно черному}

then

begin inc(M); T[M]:=u;end; {заносим карточку в результат}

end;

BuildDominators; {Строим множество доминаторов}

Reverse; {Обращаем граф}

BuildDominators2; {Строим множество доминаторов обращенного графа, попутно получая все сильносвязные компоненты графа}

Рассмотрим процедуру BuildDominators:

Procedure BuildDominators;

begin

Time:=0; {Время обработки вершин = 0}

for i:=1 to N do {Для каждой вершины i помечаем}

begin

Color[i] := WHITE; {Вершина свободна}

Dom[i] := WHITE; {Доминаторов нет}

CurC[i] := WHITE; {Свободна на текущем шаге}

F[i] := 0; {Время завершения обработки - 0}

end;

for v:=1 to N do {Для всех вершин}

if color[v]=WHITE {Если вершина v свободна}

then

begin

DFS(v); {Поиск в глубину от вершины v}

AddDominator(v); {Добавить найденного доминатора}

end;

end;

Таким образом в ходе обработки вершин графа на этом этапе у нас есть 3 множества

Dom - найденные на текущий момент доминаторы графа

Color - все обработанные вершины

CurC - вершины, обработанные во время поиска в глубину от текущей базовой вершины V

Рекурсивная процедура поиска в глубину выглядит для данной задачи таким образом:

Procedure DFS(i:byte);

var

j : byte;

begin

color[i]:=GRAY; {Вершина i обработана вообще}

curC[i]:=GRAY; {Вершина i обработана на текущем шаге}

inc(Time); {Увеличить время обработки вершин}

for j:=1 to kG[i] do {Пока у вершины есть наследники}

if curC[G[i,j]]=WHITE {Если наследник не обрабатывался на текущем шагу}

then DFS(G[i,j]); {Запустить поиск в глубину от наследника}

inc(Time); {Увеличить время обработки вершин}

if F[i]=0 {Если вершине i не устанавливалось время}

then F[i]:=Time; {завершения обработки - то установить}

end;

Процедура AddDominator(v), также вызываемая из процедуры BuildDominators, добавляет в список доминаторов вершину v следующим образом: все вершины, достигнутые из текущей (Curc[i]<>WHITE) вычеркиваем из доминаторов; текущую добавляем в список доминаторов (dom[Domi]:=GRAY;).

Procedure AddDominator (Domi:longint);

begin

for i:=1 to N do {Для всех вершин}

if (CurC[i]<>WHITE) {Если она достигнута от текущей}

then dom[i]:=WHITE; {Вычеркиваем ее из доминаторов}

dom[Domi]:=GRAY; {Вносим текущую в список доминаторов}

for i:=1 to N do {Для всех вершин устанавливем отметку}

curC[i]:=WHITE; {недостигнута от текущей}

end;

Следующий шаг за построением доминаторов исходного графа - транспонирование графа (другими словами смена стрелок на дугах на противоположные). Это делается с помощью процедуры Reverse. Процедура Reverse по исходному графу G[1..N,1..M], kg[1..N] строит граф B[1..N,1..M], kB[1..N]:

Procedure Reverse;

begin

for i:=1 to N do KB[i]:=0; {Обнуляем количества дуг из вершины i}

for i:=1 to N do

for j:=1 to kG[i] do

begin

inc(kB[G[i,j]]); {Инкрементируем количество дуг из вершины i}

b[G[i,j],kB[G[i,j]]]:=i; {Добавляем в граф обратную дугу}

end;

end;

Процедура BuildDominator2 строит множество доминаторов на транспонированном графе, параллельно формируя сильно связные компоненты (ССК) исходного графа:

Procedure BuildDominators2;

begin

Time:=0;

for i:=1 to N do {Для всех вершин}

begin

Color[i]:=WHITE; {Свободна вообще}

CurC[i] :=WHITE; {Свободна в текущем цикле}

Kart[i]:=WHITE; {Не входит в ССК}

end;

SortF; {Сортируем в порядке убывания времена завершения обработки вершин при построении множества доминаторов исходного графа - результат Q[1..N]}

for v:=1 to N do {В порядке убывания времен обработки}

if color[Q[v]]=WHITE {Если вершина свободна}

then

begin

DFS2(Q[v]); {Построить доминатора}

AddDominator2(Q[v]); {Добавить доминатора}

end;

for i:=1 to N do {Для всех вершин}

if (Kart[i]<>WHITE) {Если входит в ССК}

then begin

inc(M); {вносим в результат}

T[M]:=i;

end;

SortT; {Сортируем результирующее множество}

writeln(M); for i:=1 to M do writeln (T[i]); {выводим его}

end;

Процедура DFS2 поиска глубину по транспонированному графу выглядит следующим образом:

Procedure DFS2(i:byte);

Var j : byte;

begin

color[i]:=GRAY; curc[i]:=GRAY;

for j:=1 to kB[i] do

if color[B[i,j]]=WHITE then DFS2(B[i,j]);

end;

Процедура AddDominator2 обеспечивающая корректное построение доминаторов транспонированного графа и сильносвязных компонент исходного (и транспонированного) графов такова:

Procedure AddDominator2 (Domi:longint);

var

MinT, MinK, KS : longint;

FlDom : boolean;

begin

KS:=0; {Количество вершин в текущей ССК}

for i:=1 to N do {Для всех вершин}

if Curc[i]<>WHITE {Если вершина достигнута}

then inc(KS); {инкрементировать к-во вершин в текущей ССК}

if ks>1 {Если в текущей ССК вершин}

then {больше чем одна}

for i:=1 to N do {то внести их всех в KART}

if CurC[i]<>WHITE then Kart[i]:=GRAY;

for i:=1 to N do curC[i]:=WHITE; {Сделать все вершины свободными для нового шага}

end;

Полный текст программы, решающей поставленную задачу приводится ниже.

program by94d1t1;

Const

WHITE = 1;

GRAY = 2;

var

G,B : array [1..100,1..100] of byte;

Color,kG,kB,Dom,CurC,Kart: array [1..100] of byte;

D,F,T,Q : array [1..100] of longint;

N,i,j,Time,v,u,M,GRA_Y : longint;

Function max(a,b:longint):longint;

begin

if (a>b) then max:=a else max:=b

end;

Procedure Reverse;

begin

for i:=1 to N do KB[i]:=0;

for i:=1 to N do

for j:=1 to kG[i] do

begin

inc(kB[G[i,j]]);

b[G[i,j],kB[G[i,j]]]:=i;

end;

end;

Procedure AddDominator (Domi:longint);

begin

for i:=1 to N do

if CurC[i]<>WHITE then dom[i]:=WHITE;

dom[Domi]:=GRAY;

for i:=1 to N do curC[i]:=WHITE;

end;

Procedure DFS(i:byte);

Var j : byte;

begin

color[i]:=GRAY; curC[i]:=GRAY; inc(Time);

for j:=1 to kG[i] do

if curC[G[i,j]]=WHITE then DFS(G[i,j]);

inc(Time);

if F[i]=0 then F[i]:=Time;

end;

Procedure BuildDominators;

begin

Time:=0;

for i:=1 to N do

begin

Color[i]:=WHITE; Dom[i]:=WHITE;

CurC[i]:=WHITE; F[i]:=0;

end;

for v:=1 to N do

if color[v]=WHITE

then begin DFS(v); AddDominator(v); end;

end;

Procedure SortF;

var

i,j,MaxD,k,Temp :longint;

begin

for i:=1 to N do Q[i]:=i;

for i:=1 to N-1 do

begin

MaxD:=F[i]; K:=i;

for j:=i+1 to N do

if F[j]>MaxD

then begin MaxD:=F[j]; k:=j; end;

F[k]:=F[i]; F[i]:=MaxD; Temp:=Q[k];

Q[k]:=Q[i]; Q[i]:=Temp;

end

end;

Procedure SortT;

var

i,j,MaxD,k,Temp :longint;

begin

for i:=1 to M-1 do

begin

MaxD:=T[i]; K:=i;

for j:=i+1 to M do

if T[j]<MaxD

then begin MaxD:=T[j]; k:=j; end;

T[k]:=T[i]; T[i]:=MaxD;

end

end;

Procedure DFS2(i:byte);

var

j : byte;

begin

color[i]:=GRAY; curc[i]:=GRAY;

for j:=1 to kB[i] do

if color[B[i,j]]=WHITE then DFS2(B[i,j]);

end;

Procedure AddDominator2 (Domi:longint);

var

MinT, MinK, KS : longint;

FlDom : boolean;

begin

KS:=0;

for i:=1 to N do

if Curc[i]<>WHITE then inc(KS);

if ks>1

then

for i:=1 to N do

if CurC[i]<>WHITE then Kart[i]:=GRAY;

for i:=1 to N do curC[i]:=WHITE;

end;

Procedure BuildDominators2;

begin

Time:=0;

for i:=1 to N do

begin

Color[i]:=WHITE;

CurC[i] :=WHITE; Kart[i]:=WHITE;

end;

SortF;

for v:=1 to N do

if color[Q[v]]=WHITE

then begin DFS2(Q[v]); AddDominator2(Q[v]); end;

for i:=1 to N do

if (Kart[i]<>WHITE)

then begin inc(M); T[M]:=i;end;

SortT;

writeln(M);

for i:=1 to M do writeln (T[i]);

end;

begin

assign(input,'input.txt'); reset(input);

assign(output,'output.txt'); rewrite(output);

readln(N);

M:=0;

for i:=1 to N do

begin

readln(u,v);

inc(kG[u]); G[u,kG[u]]:=v;

if u=v then begin inc(M); T[M]:=u;end;

end;

BuildDominators;

Reverse;

BuildDominators2;

close(input); close(output);

end.

4.2 Задача "Межшкольная сеть"

IOI'96 - Международная олимпиада по информатике (Венгрия)

Некоторые школы связаны компьютерной сетью. Между школами заключены соглашения: каждая школа имеет список школ получателей, которым она рассылает программное обеспечение всякий раз, получив новое бесплатное программное обеспечение (извне сети или из другой школы). При этом, если школа В есть в списке получателей школы А, то школа А может и не быть в списке получателей школы В.

Требуется написать програму, определяющую минимальное количество школ, которым надо передать по экземпляру нового программного обеспечения, что бы распространить его по всем школам сети в соответствии с соглашениями (подзадача А).

Кроме того, надо обеспечить возможность рассылки нового программного обеспечения из любой школы по всем остальным школам. Для этого расширить списки получателей некоторых школ, добавляя в них новые школы. Требуется найти минимальное суммарное количество расширений списков, при которых программное обеспечение из любой школы достигло бы остальных школ (подзадача В). Одно расширение означает добавление одной новой школы-получателя в список получателей одной из школ.

Входные данные

Первая строка файла INPUT.TXT содержит целое число N - количество школ в сети (2<=N<=100). Школы нумеруются первыми N положительными целыми числами. Каждая из следующих N строк задает список получателей. Строка i+1 содержит номера получателей i-й школы. Каждый такой список заканчивается нулем. Пустой список содержит только 0.

Выходные данные

Ваша программа должна записать 2 строки в файл OUTPUT.TXT. Его первая строка должна содержать одно положительное целое число - решение подзадачи А. Вторая строка должна содержать решение подзадачи B.

Пример ввода и вывода

INPUT.TXT

5

2 4 3 0

4 5 0

0

0

1 0

OUTPUT.TXT

1

2

Подазадача A требует найти доминантное множество - то есть минимальное множество вершин исходного графа, из которого есть цепи ко всем остальным вершинам графа.

Обходом в глубину пока есть свободные (неперекрашенные из белого в серый цвет) вершины находим все, которые достижимы из нее. И из множества доминант вычеркиваем все достижимые на текущем ходу и добавляем в множество доминант исходную свободную.

Подзадача B требует найти количество ребер, которые нужно добавить, что бы исходный ориентированный граф стал сильно связным. По исходному графу строится транспонированный (стрелки на дугах меняются на противоположные). И для нового (транспонированного) графа опять строятся доминантное множество.

Если и первое и второе доминантное множество состоят из одного и того же элемента - вершины 1, то граф был сильносвязный и добавлять ребер не нужно. Иначе нужно добавить максимум из количеств элементов в построенных доминантных множествах.

Поскольку практически почти такая же задача полностью рассмотрена в предыдущем пункте, полное описание решения здесь не приводится.

Другое решение этой же задачи:

Методом Флойда строим матрицу достижимости.

В результате все вершины разбиваются на группы

- истоки (в них нет входящих дуг)

- стоки (из них нет исходящих дуг)

- промежуточные (есть и входящие и исходящие)

Ответ подзадачи A - количество истоков

Для подзадачи B:

Если нет ни истоков, ни стоков, то граф - ССК (сильносвязная компонента) и добавлять ребер не нужно. Иначе, выбираем максимальное из количеств истоков и стоков - это и есть количество ребер которые нужно добавить.

Пояснение: Добавляем связи между истоками и стоками в результате чего граф и становится сильносвязной компонентой

4.3 Задача "Винни-Пух и Пятачок" (Автор - Котов В.М.)

Республика, школьники, 1995г.

Винни-Пух и Пятачок нанялись защищать компьютерную сеть от хаккеров, которые выкачивали из компьютеров секретную информацию. Компьютерная сеть Винни-Пуха и Пятачка состояла из связанных между собой больших ЭВМ, к каждой из которых подключалось несколько терминалов. Подключение к одной из больших ЭВМ позволяло получить информацию, содержащуюся в памяти этой ЭВМ, а также всю информацию, доступную для ЭВМ, к которым данная ЭВМ могла направлять запросы. Хаккеры и раньше нападали на подобные компьютерные сети и их тактика была известна. Поэтому Винни-Пух и Пятачок разработали специальную программу, которая помогла принять меры против готовившегося нападения.

Тактика хаккеров.

При нападениях хаккеры всегда получают доступ к информации всех ЭВМ сети. Добиваются они этого, захватывая некоторые ЭВМ сети, так чтобы от них можно было запросить информацию у оставшихся ЭВМ. Вариантов захвата существует множество.

Например, захватить все ЭВМ. Но хаккеры всегда выбирают такой вариант, при котором суммарное количество терминалов у захваченных ЭВМ минимально.

Примечание.

В сети Винни-Пуха и Пятачка ни у каких 2-х ЭВМ количество терминалов не совпадает.

Техническое задание.

Вам необходимо написать программу, входными данными которой было бы описание сети, а выходными - список номеров ЭВМ, которые могут быть выбраны хаккерами для захвата сети согласно их тактике. Ввод осуществляется из файла с именем INPUT.TXT. Возможен ввод с клавиатуры.

Формат ввода.

Количество ЭВМ в сети : N

ЭВМ #1 имеет терминалов : T[1]

ЭВМ #2 имеет терминалов : T[2]

...

ЭВМ #N имеет терминалов : T[N]

Права на запрос :

A[1] B[1]

A[2] B[2]

...

A[K] B[K]

0 0

A[i] и В[i] - номера ЭВМ, последняя строка '0 0' обозначает конец списка прав на запрос, каждая пара A[i] B[i] обозначает, что ЭВМ с номеров A[i] имеет право запрашивать информацию у ЭВМ с номером B[i] (A[i] не равно B[i]).

При вводе числа N и T[i] - натуральные, T[i] <=1000, N<=50, K<=2450.

Входные данные соответствуют приведенным условиям.

Формат вывода.

Номера захватываемых ЭВМ : С[1] C[2] ... С[M].

Количество захватываемых ЭВМ : <M>

Input.txt

5

100

2

1

3

10

1 3

3 2

4 3

4 5

5 4

0 0

Output.txt

1 4

2

Поиском в глубину находим множество доминаторов сети. (истоки графа). Однако для оптимального выбора машин по количеству терминалов необходимо выбрать лучшую машину (с наименьшим количеством терминалов) в каждой сильно связной компоненте.

Для этого инвертируем граф (меняем направление всех дуг графа на противоположное) и поиском в глубину по инвертированному графу находим все его сильно связные компоненты (последовательные деревья, которые получаются поиском в глубину.). Нас интересуют только сильно связные компоненты с количеством вершин больше 1. В этом случае находим из них вершину с минимальным количеством терминалов и заменяем соответствующий доминатор (если от этой ССК ранее в доминаторы попала другая вершина).

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

5. Поиск в ширину

5.1 Задача "Уличная гонка"

IOI'95 - Международная олимпиада по информатике (Голландия)

1 4 7

/ \ / \ / \

/ \ / \ / \

/ \ / \ / \

0 3 6 9

\ / \ / \ /

\ / \ / \ /

\ / \ / \ /

2 5 <---8

Вы видите точки, помеченные числами от 0 до N (где N=9), а также стрелки, соединяющие их. Точка 0 является стартовой; точка N - финишной. Стрелками представлены улицы с односторонним движением. Участники гонки передвигаются от точки к точке по улицам только в направлении стрелок. В каждой точке участник гонки может выбрать любую из исходящих стрелок.

Назовем план улиц хорошим, если он обладает следующими свойствами:

1. Каждая точка плана может быть достигнута со старта.

2. Финиш может быть достигнут из любой точки плана.

3. У финиша нет исходящих стрелок.

Для достижения финиша участник не обязан пройти через все точки. Однако некоторые точки невозможно обойти. Назовем их неизбежными. В примере такими точками являются точки 0, 3, 6, 9. Для заданного хорошего плана Ваша программа должна определить множество неизбежных точек (за исключением старта и финиша), которые должны посетить все участники (подзадача А).

Предположим, что гонка должна проводиться за два последовательных дня. Для этой цели план должен быть разбит на два хороших плана, по одному на каждый день. В первый день стартом является точка 0,а финишем служит некая "точка разбиения". Во второй день старт находится в этой точке разбиения,а финиш находится в точке N. Для заданного хорошего плана Ваша программа должна определить множество всех возможных точек разбиения (подзадача В).

Точка S является точкой разбиения для хорошего плана С, если S отличается от старта и финиша С, и план разбивается ею на два хороших плана без общих стрелок и с единственной общей точкой S. В примере точкой разбиения является точка 3.

ВХОДНЫЕ ДАННЫЕ

В файле INPUT.TXT описан хороший план, содержащий не более 50 точек и не более 100 стрелок. В файле имеется N+1 строка. Первые N строк содержат конечные точки стрелок, исходящих соответственно из точек от 0 до N-1. Каждая из этих строк заканчивается числом -2. В последней строке содержится число -1.

ВЫХОДНЫЕ ДАННЫЕ

Ваша программа должна записать две строки в файл OUTPUT.TXT. Первая строка должна содержать количество неизбежных точек в заданном плане, после чего в той же строке должны следовать номера этих точек в любом порядке (подзадача А). Вторая строка должна содержать количество точек в заданном плане, за которым в той же строке должны следовать номера этих точек в любом порядке(подзадача В).

ПРИМЕР ВВОДА И ВЫВОДА

INPUT.TXT OUTPUT.TXT

1 2 -2 2 3 6

3 -2 1 3

3 -2

5 4 -2

6 4 -2

6 -2

7 8 -2

9 -2

5 9 -2

-1

Для решения подзадачи A нужно найти все неизбежные точки. Это делается поиском в ширину - если после взятия вершины из очереди очередь становится пустой - то эта вершина - НЕИЗБЕЖНАЯ.

Для решения подзадачи B нужно проверить каждую НЕИЗБЕЖНУЮ точку, является ли она точкой разбиения. Для этого удаляем эту точку из графа и поиском в ширину строим 2 множества - ДОСТИЖИМЫЕ точки от начала, и недостижимые точки от начала.

Если существует хоть одно ребро из недостижимой точки в достижимую - то текущая НЕИЗБЕЖНАЯ точка не является возможной точкой разбиения (по определению точки разбиения).

Рассмотрим алгоритм решения задачи более подробно, основываясь на исходном тексте программы, решающей поставленную задачу:

Тело главной программы выглядит следующим образом:

InputData; {Ввод исходных данных}

BFS; {Поиск в ширину - находим "неизбежные" точки}

OutSubA; {Вывод ответа для подзадачи A}

for k:=1 to SubA do {Для каждой неизбежной точки}

begin

DelArcs(Duty[k]); {Удаляем неизбежную точку}

BFS; {Поиск в ширину -}

{Строим множества достижимых Color[i]=1}

{и недостижимых Color[i]=0 вершин}

RetArcs(Duty[k]); {Возвращаем неизбежную точку в граф}

for i:=0 to N-1 do {Для всех веришин}

begin

j:=1; {j - номер дуги, исходящей из вершины}

while (a[i,j]>=0) do {пока дуга существует}

begin

if (color[i]=WHITE) and {Если исходная вершина достижима}

(color[a[i,j]]<>WHITE) {а "конец дуги" - не достижима}

then begin

Duty[k]:=0; {Это - НЕ точка разбиения}

break {Перейти к проверке следующей}

end; {неизбежной точки}

inc(j); {Взять следующую дугу}

end;

end;

end;

OutSubB; {Вывод ответа для подзадачи B}

Процедура ввода исходных данных:

Procedure Inputdata;

begin

i:=0; j:=1; read(a[0,1]); {начинаем ввод с вершины 0}

while (a[i,j]<>-1) do {Пока не закончена обработка вершин}

begin

while(a[i,j]<>-2) do {Пока не закончена обработка дуг}

begin

inc(j); {Увеличить номер дуги}

read(a[i,j]) {Прочитать дугу}

end;

if j >2 then Sort; {Если дуг больше чем одна, то}

{отсортировать их по возрастанию}

{номера конечной вершины}

readln; inc(i); {Перейти к считыванию следующей строки}

j:=1; read(a[i,j]); {Прочитать первый элемент строки}

end; {Вернуться к началу цикла ПОКА}

N:=i; {Занести в N номер последней вершины}

end;

Поиск в ширину осуществляется с помощью процедуры BFS (Breadth-First Search).

procedure BFS;

var i,j : longint;

begin

for i:=0 to N do color[i]:=WHITE; {Все вершины свободны}

color[0]:=GRAY; {Начальная вершина - обработана}

SubA:=0; {Количество неизбежных вершин = 0}

BegQ:=1; {Начало очереди}

EndQ:=0; {Очередь пуста}

Put(0); {Поместить в очередь начальную вершину}

while (BegQ<=EndQ) do {Пока очередь не пуста}

begin

Get(i); {Взять вершину i из очереди}

if BegQ>EndQ {Если очередь осталась пустой}

then

begin

inc(SubA); {инкрементировать количество}

{неизбежных вершин}

Color[i]:=ColSubA {Пометить неизбежную вершину}

end;

j:=1; {номер дуги из вершины i}

while (a[i,j]>=0) do {пока дуги не кончились}

begin

if color[a[i,j]]=WHITE {если вершина a[i,j] свободна}

then

begin

Put(a[i,j]); {поставить ее в очередь}

color[a[i,j]]:=GRAY; {пометить вершину a[i,j]}

end; {как использованную}

inc(j); {взять следующую дугу}

end;

end;

end;

Вывод ответа для подзадачи A и накопление неизбежных точек в массив Duty осуществляется так:

procedure OutSubA;

begin

SubA:=subA-2; {Начальная и конечная точки не}

write(subA); {считаются неизбежными точками}

j:=0; {J - количество неизбежных точек}

for i:=1 to N-1 do {Для всех вершин}

if (color[i]=ColSubA) {Если она - неизбежная}

then

begin

write(' ',i); {Выводим ее}

inc(j); {Инкрементируем к-во неизбежных вершин}

Duty[j]:=i; {Запоминаем номер неизбежной вершины}

end;

writeln;

end;

Далее приводится полный текст решения задачи

program io96d2t4;

Const

White = 1;

Gray = 2;

ColSubA = 4;

var

A : array [0..101,0..101] of integer;

Color,Q,Duty : array [0..100] of integer;

N,i,j,subA,SubB,BegQ,EndQ,k : longint;

Procedure Put(x:longint);

Begin inc(EndQ); Q[EndQ]:=x; end;

Procedure Get(var x:longint);

Begin x:=Q[BegQ]; inc(BegQ); end;

Procedure Sort;

var

m,min,rmin,k : longint;

begin

for m:=1 to j-2 do

begin

min:=a[i,m]; rmin:=m;

for k:=m+1 to j-1 do

if a[i,k]<min

then begin min:=a[i,k]; rmin:=k; end;

a[i,rmin]:=a[i,m]; a[i,m]:=min;

end;

end;

Procedure Inputdata;

begin

i:=0; j:=1; read(a[0,1]);

while (a[i,j]<>-1) do

begin

while(a[i,j]<>-2) do

begin inc(j); read(a[i,j]) end;

if j >2 then Sort;

readln;

inc(i); j:=1; read(a[i,j]);

end;

N:=i;

end;

procedure OutSubA;

begin

SubA:=subA-2; write(subA); j:=0; Duty[0]:=0;

for i:=1 to N-1 do

if (color[i]=ColSubA)

then begin write(' ',i); inc(j); Duty[j]:=i; end;

writeln;

end;

procedure BFS;

var i,j : longint;

begin

for i:=0 to N do color[i]:=WHITE;

for i:=0 to N do Q[i]:=0;

color[0]:=GRAY; SubA:=0; BegQ:=1; EndQ:=0;

Put(0);

while (BegQ<=EndQ) do

begin

Get(i);

if BegQ>EndQ

then begin inc(SubA); Color[i]:=ColSubA end;

j:=1;

while (a[i,j]>=0) do

begin

if color[a[i,j]]=WHITE

then begin

Put(a[i,j]);

color[a[i,j]]:=GRAY;

end;

inc(j);

end;

end;

end;

Procedure OutSubB;

begin

SubB:=0;

for i:=1 to SubA do

if Duty[i]<>0 then inc(SubB);

write(subB);

for i:=1 to SubA do

if Duty[i]<>0 then write(' ',Duty[i]);

writeln;

end;

Procedure DelArcs(k:longint);

begin

for j:=N Downto 1 do a[k,j+1]:=a[k,j];

a[k,1]:=-2;

for i:=0 to N-1 do

begin

j:=1;

while (a[i,j]>=0) do

begin

if a[i,j]=k then a[i,j]:=maxint;

inc(j);

end;

end;

end;

Procedure RetArcs(k:longint);

begin

for i:=0 to N-1 do

begin

j:=1;

while (a[i,j]>=0) do

begin

if a[i,j]=maxint then a[i,j]:=k;

inc(j);

end;

end;

for j:=1 to N do a[k,j]:=a[k,j+1]

end;

begin

assign(input,'input.txt'); reset(input);

assign(output,'output.txt'); rewrite(output);

InputData;

BFS; {Поиск в ширину - находим "неизбежные" точки}

OutSubA;

for k:=1 to SubA do

begin

DelArcs(Duty[k]); BFS; RetArcs(Duty[k]);

for i:=0 to N-1 do

begin

j:=1;

while (a[i,j]>=0) do

begin

if (color[i]=WHITE) and (color[a[i,j]]<>WHITE)

then begin Duty[k]:=0; break end;

inc(j);

end;

end;

end;

OutSubB;

close(input); close(output);

end.

6. О размерностях использованных в задачах массивов

Внимательный читатель обратил внимание, что в некоторых случаях массивы объявлены меньшей размерности, чем реально требуется по условиям задачи. Это сделано намеренно из следующих соображений.

A. На международных олимпиадах по информатике для школьников с июля 2001 года используются 32-битные компиляторы (Free Pascal и GNU C), для которых разрешаемые размерности объявляемых массивов существенно больше чем те, что требуются по условиям задачи.

B. Основная цель материала - продемонстрировать предлагаемые базовые алгоритмы решения задач на графах, и не хотелось усложнять материал, затемняя тем самым суть базовых алгоритмов.

C. Возможно, методам эффективного использования оперативной памяти будет посвящена отдельная статья.

Заключение

Цель данного пункта коротко перечислить приведенные в данном материале теоретические сведения для решения задач на графах. Читатель может использовать этот перечень для самоконтроля успешности усвоения данного материала. Если Вы понимаете, что скрывается под приведенным названием и умеете выполнять названную работу - значит цели, поставленные автором (и Вами) достигнуты.

Вот этот перечень вопросов для самоконтроля:

- о сведении задач к графам

- метод Флойда, применяется для

- поиска кратчайших расстояний расстояний между всеми парами вершин графа (одновременно можно построить и сами кратчайшие пути от каждой вершины до каждой)

- построения матрицы достижимости графа

- построения множества истоков и множества стоков (исток - вершина, в которую нет входящих дуг) (сток - вершина, из которой нет исходящих дуг)

- метод Дейкстра, применяется для

- поиска кратчайших расстояний от одной вершины до всех остальных

- построения оптимальных маршрутов от одной вершины до всех остальных

- поиск в глубину, применяется для

- решения произвольных задач на графах, требующих соответствующего порядка обхода ("в глубину") графа;

- построения множества истоков и стоков (как истоков на транспонированном графе)

- построения сильносвязных компонент (ССК) графа ССК - это множество вершин, каждая из которых достижима из всех вершин ССК

- поиск в ширину, применяется для

- решения произвольных задач на графах, требующих соответствующего порядка обхода ("в ширину") графа;

Литература

1. М. Долинский "Памятка участнику олимпиады по информатике среди школьников", "Радиолюбитель. Ваш компьютер", Минск, No 1, 2000 с.20-21.

2. М. Долинский "Начинаем программировать самостоятельно", "Радиолюбитель. Ваш компьютер", Минск, No 1, 2000, с.23-24, No 2, 2000, с.22-23, No 3, 2000, с.23-25, No 4, 2000, с.26-27, No 5, с.27-28, No 6, с.23-26.

3. М. Долинский "Решение задач на тему "Геометрия на плоскости", "Радиолюбитель. Ваш компьютер", Минск, 2000, No 8, с.21-23, 2000, No 9, с.19-21.

4. М. Долинский "Разработка программ с использованием определяемых программистом типов данных", "Радиолюбитель. Ваш компьютер", Минск, 2001, No 1, 2001, с.29-31, No 3, с. 26-28.

5. М. Долинский " Решение задач с помощью очереди и стека" , Минск, "Радиолюбитель. Ваш компьютер", No 4, 2001, с.26-27, No 5, с.27-28, No 6, с.24-25.

6. М. Долинский " Обзор возможностей языка программирования Паскаль", Москва, Радиомир. Ваш компьютер", No 7, 2001, с.23-25.

7. М. Долинский "Алгоритмы генерации комбинаторных объектов" "Радиолюбитель. Ваш компьютер", (принята к публикации).

8. М. Долинский "Некоторые факты из теории чисел" "Радиолюбитель. Ваш компьютер", (принята к публикации).

9. М. Долинский "Использование рекурсивных функций и процедур" "Радиолюбитель. Ваш компьютер", (принята к публикации).

10. М. Долинский "Решение задач с помощью рекуррентных соотношений" "Радиолюбитель. Ваш компьютер", (принята к публикации).

11. Котов В.М., Волков И.А., Харитонович А.И. "Методы алгоритмизации" Учебное пособие для 8-го класса общеобразовательной школы с углубленным изучением информатики, Мн., "Народная асвета", 1996, 127 с.

12. Котов В.М., Волков И.А., Лапо А.И. "Методы алгоритмизации" Учебное пособие для 9-го класса общеобразовательной школы с углубленным изучением информатики, Мн., "Народная асвета", 1997, 160 с.

13. Котов В.М., Мельников О.И. "Методы алгоритмизации" Учебное пособие для 10-11-го классов общеобразовательной школы с углубленным изучением информатики, Мн., "Народная асвета", 2000, 221 с.


Подобные документы

  • Определение понятия графа как набора вершин и связей между ними. Способы решения задач по программированию согласно теории графов на примерах заданий "Дороги", "Перекрестки", "Скрудж Мак-Дак", используя рекурсивные функции и рекуррентные соотношения.

    курсовая работа [36,2 K], добавлен 10.03.2010

  • Описание методов нахождения и построения эйлеровых циклов в графах при раскрытии содержания цикломатических чисел и фундаментальных циклов. Изучение алгоритма решения задачи "Китайского почтальона" и разработка программы, решающей задачу на языке Си.

    курсовая работа [924,3 K], добавлен 09.01.2011

  • Решение типовых задач с помощью языка программирования Turbo Pascal и табличного процессора Microsoft Excel 2007. Обратная геодезическая задача, прямая угловая задача, обратная геодезическая засечка, решение системы линейных уравнений методом Гаусса.

    курсовая работа [1,3 M], добавлен 11.01.2011

  • Задача о ранце как задача комбинаторной оптимизации. Задача о загрузке, рюкзаке, ранце. Постановка и NP-полнота задачи. Классификация методов решения задачи о рюкзаке. Динамическое программирование. Метод ветвей и границ. Сравнительный анализ методов.

    курсовая работа [1,7 M], добавлен 18.01.2011

  • Основные понятия и определения алгоритмов на графах. Связные графы без циклов, свободное дерево или дерево без корня. Ориентированные графы (орграфы), их использование для представления отношений между объектами. Матрицы смежности и инциденций.

    презентация [93,9 K], добавлен 13.09.2013

  • Задача о кратчайшем пути как одна из важнейших классических задач теории графов. Общий обзор трех наиболее популярных алгоритмов для решения задачи о кратчайшем пути. Написание программы, которая реализует алгоритм Дейкстры и алгоритм Форда-Беллмана.

    курсовая работа [2,1 M], добавлен 23.06.2014

  • Задача о восьми ферзях как широко известная задача по расстановке фигур на шахматной доске. Характеристика алгоритмов решения задачи для доски 8х8. Рассмотрение особенностей программы, использующей алгоритм Лас-Вегаса, проведения статистического анализа.

    контрольная работа [382,3 K], добавлен 06.08.2013

  • Визначення та способи представлення графів. Основні алгоритми на графах. Побудова мінімального остового дерева. Алгоритми Прима та Дейкстри. Модель Флойда-Уоршалла. Огляд можливостей мови програмування. Опис функцій програмної моделі, інтерфейс програми.

    дипломная работа [563,7 K], добавлен 03.08.2014

  • Условия математической транспортной задачи для ее решения методом потенциалов. Опорный план и проверка целевой функции. Окончательный вариант плана поставок товара предоставленный программой "АОС транспортная задача". Стоимость доставки единицы груза.

    лабораторная работа [1,4 M], добавлен 15.10.2015

  • Нормальный алгоритм Маркова. Тезис Маркова и машина Тьюринга. Гипотеза теории алгоритмов. Алгоритмически неразрешимые проблемы. Задача эквивалентности двух слов в ассоциативном исчислении. Задача распознавания выводимости. Линейная оценка сложности.

    методичка [57,0 K], добавлен 06.07.2009

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.