【NOIP2013模拟】开心小屋 (Standard IO)
Memory Limits: 262144 KB
Description
Kc来到开心小屋。开心小屋是用来提升心情的。在这个小屋中有n个房间,一些房间之间有门连通。从房间i到达房间j,心情值可以加上-10000<=Cij<=10000,当然Cij可能是负的。现在kc失恋了,所以他想要知道他是否可以在这个小屋中无限地增加他的心情值,也就是无限地绕着一个环走?
请帮kc求出最小的环需要经过的房间数,来使他的心情无限增加。
Input
第一行给出,1<=n<=300,1<=m<=5000。分别表示房间数及门的数量。
接下来m行,每行四个数:i,j,Cij,Cji
Output
输出文件包括一行,及最小的环需要经过的房间数。
保证不会出现自环及重边。
Sample Input
4 4
1 2 -10 3
1 3 1 -10
2 4 -10 -1
3 4 0 -3
Sample Output
4
样例解释:
1—>3—>4–>2–>1为最小的符合题意的环长度为4.
Data Constraint
对30%的数据,n<=10;
对60%的数据,,n<=100;
对100%的数据,n<=300;
此题有个比较难理解的地方:最小的环需要经过的房间数,有一些指代不明(最小的环,它所经过的个数;所有环经房间个数的最小值)。
经过反复试验,发现它指的是后者。
现在,讲讲解题的方法:
——明显就是暴搜
枚举每一个起始点,递归寻环,将环的长度更新答案,环的长度用前缀和计算。
——但是这样肯定会超时,所以我们需要几个小小的剪枝,然而就是这些剪枝起了大大的作用。
- 倘若当次递归所搜过的屋子个数超过了先前找的答案,exit掉。
- 倘若从起点到当前位置,它的值已经成了负数,exit掉。
codes:
var a,r:array[1..300,0..300]of longint;
bz:array[1..300]of boolean;
f,num:array[1..300]of longint;
n,m,x,y,z1,z2,i,sum:longint;
procedure doit(n,v,t:longint);
var o,x,y:longint;
begin
if v<0 then exit;
if t>=sum then exit;
if bz[n] then
begin
if v-f[n]<=0 then exit;
if t-num[n]<sum then sum:=t-num[n];
exit;
end;
bz[n]:=true;
f[n]:=v; num[n]:=t;
for o:=1 to a[n,0] do
begin
x:=a[n,o]; y:=r[n,o];
doit(x,v+y,t+1);
end;
bz[n]:=false;
end;
begin
read(n,m);
for i:=1 to m do
begin
read(x,y,z1,z2);
inc(a[x,0]);
a[x,a[x,0]]:=y; r[x,a[x,0]]:=z1;
inc(a[y,0]);
a[y,a[y,0]]:=x; r[y,a[y,0]]:=z2;
end;
sum:=maxlongint;
for i:=1 to n do doit(i,0,0);
writeln(sum);
end.