Задача Заданы N-вершинный ориентированный граф с двумя выделенными вершинами v1 и v2 и целое число C. Требуется:Определить, существует ли в заданном графе путь из вершины v1 в вершину v2, состоящий из C ребер (путь может иметь самопересечения как по вершинам, так и по ребрам)
Найти минимум функции |X - C|, где X - количество ребер в некотором пути из v1 в v2
Входные данные Первая строка входного файла содержит целое число N - количество вершин в графе (1 N 10). В следующих N строках расположена матрица N×N из нулей и единиц, элемент (i,j) которой равен единице, если в графе есть ребро из вершины i в вершину j, и нулю, если такого ребра нет. (Граф может содержать петли, т.е. ребра, идущие из вершины в саму себя.) Элементы матрицы во входном файле записаны без разделительных пробелов Наконец, строка N+2 содержит номера вершин v1 и v2, а строка N+3 - десятичную запись числа C (1 C<1050) Выходные данные В первую строку выходного файла выведите ответ на первый пункт задачи: "Yes", если путь длины C существует, и "No" в противном случае. Во вторую строку запишите ответ на второй пункт задачи. Если ни одного пути из v1 в v2 не существует, ваша программа должна вывести в выходной файл число "-1" Например: GRPATH.IN 3 010 001 100 1 1 555555555555555555555555555555555 GRPATH.OUT Yes 0 Идеи Зацикливание, динамическое программирование, графы, длинная арифметика. Комментарии Достаточно решить второй пункт задачи. Пусть Аi - множество вершин, в которые мы можем попасть из вершины vi, пройдясь по k ребрам. Будем последовательно вычислять множества A0, A1, A2 и т.д. Когда какое-то из этих множеств повторится, это означает, что рассматриваемая последовательность вошла в цикл (а это произойдет не позднее, чем через 2N 210 = 1024 шагов). Если число С достаточно большое, то с помощью деления определяем позицию цикла, которой оно соответствует. Далее находим ближайшее к этой позиции множество, содержащее v2. Здесь нужно внимательно разобрать возможные случаи, не забывая про существование предпериода Упражнение Решите ту же самую задачу методом динамического программирования при ограничении N 50 Решение {$A+,B-,D+,E-,F-,G-,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+,Y+} {$M 65520,0,655360} program grpath; const nMax = 10; maxPeriod = 1100; maxLen = 1000; type tPos = set of 1..10; tNum = array[0..maxLen] of integer; var a : array[1..nMax, 1..nMax] of boolean; c, oldc : tNum; n, v1, v2 : integer; perL, predL : integer; allPos : array[0..2*maxPeriod+1] of tPos; min : integer; procedure init; var s : string; i, j : integer; begin assign(input, 'grpath.in'); reSet(input); readLn(N); for i := 1 to N do begin readLn(s); for j := 1 to N do a[i, j] := s[j] = '1'; end; readLn(v1, v2); readLn(s); c[0] := length(s); for i := 1 to c[0] do c[i] := ord(s[c[0]-i+1])-ord('0'); oldc := c; end; procedure getNext(var pos : tPos); var i, j : integer; next : tPos; begin next := []; for i := 1 to N do if i in pos then for j := 1 to N do if a[i, j] then include(next, j); pos := next; end; procedure findPeriod; var pos, next : tPos; i : integer; begin pos := [v1]; allPos[1] := pos; for i := 1 to 2*maxPeriod do begin getNext(pos); allPos[i+1] := pos; end; next := pos; getNext(next); perL := 1; while next <> pos do begin getNext(next); inc(perL); end; pos := [v1]; next := [v1]; for i := 1 to perL do getNext(next); predL := 0; while next <> pos do begin inc(predL); getNext(next); getNext(pos); end; end; function toNum(const c : tNum) : longint; var num, i : longint; begin num := 0; for i := c[0] downto 1 do num := num*10+c[i]; toNum := num; end; procedure dec(var a : tNum; n : integer); var b : tNum; r, i : integer; begin fillChar(b, sizeOf(b), 0); while n <> 0 do begin inc(b[0]); b[b[0]] := n mod 10; n := n div 10; end; r := 1; for i := 1 to a[0] do begin r := a[i]-b[i]+9+r; a[i] := r mod 10; r := r div 10; end; while (a[0] > 0) and (a[a[0]] = 0) do system.dec(a[0]); end; function Less(const c : tNum; num : integer) : boolean; var a, i : longint; begin if c[0] > 4 then Less := false else Less := toNum(c) < num; end; function _mod(var c : tNum; k : integer) : integer; var ans : longint; i : integer; begin ans := 0; for i := c[c[0]] downto 1 do ans := (ans*10+c[i]) mod k; _mod := ans; end; procedure search(k, down, up : integer; cycle : boolean); var i : integer; begin min := maxInt; i := k; while (i >= down) and not (v2 in allPos[i]) do system.dec(i); if i >= down then begin min := k-i; if cycle and (min > perL-min) then min := perL-min; end; i := k; while (i <= up) and not (v2 in allPos[i]) do inc(i); if (i <= up) and (min > i-k) then begin min := i-k; if cycle and (min > perL-min) then min := perL-min; end; if (min = maxInt) and cycle then begin i := predL; while (i > 0) and not (v2 in allPos[i]) do system.dec(i); if i > 0 then begin min := -1; dec(oldc, i-1); end; end; end; procedure print; var i : integer; begin assign(output, 'grpath.out'); reWrite(output); if min = 0 then writeLn('Yes') else writeLn('No'); if (min <> -1) and (min < maxInt) then writeLn(min) else if min = -1 then begin for i := c[0] downto 1 do write(oldc[i]); writeLn; end else writeLn(-1); end; Begin init; findPeriod; if Less(c, perL+predL) then search(toNum(c)+1, 1, predL+perL, false) else begin dec(c, predL); search(_mod(c, perL)+predL+1, predL+1, predL+perL, true); end; print; close(input); close(output) End.
|