题意:给定一个带权有向图,求点数最小的负环。
2 ⩽ n ⩽ 300
0 ⩽ m ⩽ n(n - 1)
1 ⩽ ui,vi ⩽ n
abs(w[j])<= 10^4
思路:倍增思想
设d[i,j,k]为走不多于2^i次步,从j走到k的最小权值和
显然d[i]可以由d[i-1]推出
f[i,j]表示当前走若干步后从i到j的最小权值和
从大到小枚举在原来的基础上再走不多于2^i步的结果
如果有负环就不用再走2^i步,将f复原
否则将j更新为走2^i步之后的数值,继续枚举
1 const oo=1000000000; 2 var d:array[0..9,1..300,1..300]of longint; 3 g,f:array[1..300,1..300]of longint; 4 n,m,i,j,k,t,ans,x,y,z:longint; 5 flag:boolean; 6 7 function min(x,y:longint):longint; 8 begin 9 if x<y then exit(x); 10 exit(y); 11 end; 12 13 begin 14 assign(input,'cycle.in'); reset(input); 15 assign(output,'cycle.out'); rewrite(output); 16 readln(n,m); 17 for i:=1 to n do 18 for j:=1 to n do 19 if i<>j then d[0,i,j]:=oo; 20 for i:=1 to m do 21 begin 22 readln(x,y,z); 23 d[0,x,y]:=min(d[0,x,y],z); 24 end; 25 for t:=1 to 8 do 26 begin 27 for i:=1 to n do 28 for j:=1 to n do 29 if i<>j then d[t,i,j]:=oo; 30 for i:=1 to n do 31 for j:=1 to n do 32 for k:=1 to n do d[t,i,k]:=min(d[t,i,k],d[t-1,i,j]+d[t-1,j,k]); 33 end; 34 for i:=1 to n do 35 for j:=1 to n do 36 if i<>j then f[i,j]:=oo; 37 for t:=8 downto 0 do 38 begin 39 for i:=1 to n do 40 for j:=1 to n do g[i,j]:=f[i,j]; 41 for i:=1 to n do 42 for j:=1 to n do 43 for k:=1 to n do f[i,k]:=min(f[i,k],g[i,j]+d[t,j,k]); 44 flag:=false; 45 for i:=1 to n do 46 if f[i,i]<0 then begin flag:=true; break; end; 47 if flag then 48 begin 49 for i:=1 to n do 50 for j:=1 to n do f[i,j]:=g[i,j]; 51 end 52 else ans:=ans+(1<<t); 53 end; 54 inc(ans); 55 if ans>n then writeln(0) 56 else writeln(ans); 57 58 close(input); 59 close(output); 60 end.