Description
恐怖组织首领本拉登打算摧毁一个敌对势力的石油运输系统。这个石油运输系统可以看成是一个运输网络,由许多的节点和连接节点的管道构成。只有地点A生产石油,而生产的石油则通过管道输送到地点B,石油不能在中间节点累积。管道是双向的,每条管道有一个抗压指数,当石油的流量超过这个数时管道就会爆炸。A地生产石油的速度可以认为是非常快的,但由于管道抗压指数的原因,能运到B的有一个上限。本拉登知道敌对势力采用了某种方案使得他们能输送最多的石油,但他不知道这个具体的方案使什么。本拉登有一种特殊的物质,可以让一条管道的抗压指数下降1。作为恐怖组织的首席程序员,你的任务就是告诉本拉登,让哪些管道的抗压指数下降,一定可以使管道爆炸从而摧毁运输网络。
Input
第一行包含四个整数n m s t,表示有n个节点(编号为1,2,3….n),m条管道,s t分别是A地和B地的编号。2<=n<=130,0<=m<=n*(n-1)/2,1<=s,t<=n.
接下来m行每行描述一条管道,包含三个整数i j c.i和j分别为管道连接的两个节点,c为这条管道的抗压指数。1<=I,j<=n,1<=c<=10000.
Output
第一行输出抗压指数减少1就必定爆炸的管道的条数k.
接下来k行每行输出一个整数p(1<=p<=m),说明第p条管道如果抗压指数减少1就必定爆炸。序号p按照管道输入的顺序,并按照p的升序输出。
分析
这题的题意就是给你一张图,每条边上有流量,类似网络流一样流。问存在哪些边是一定在最大流里面的,即一定出现在最大流里面。
对于这样的一个问题,我们在残量网络里面研究,那么若一条边一定存在,那么这条边在残量网络里面一定是满流的。
当然除了这一点,还要满足其他的条件。就如题目上说的,容量减少1,判断是否还是原来的流量即可。但是我们这样去“爆搜”是会超时的。所以我们考虑其他的方法。
我们从“一定存在”定义入手:也就是说这条边(u,v),u->v一定只能u->v。不能经过其他的边走到v。我们从这一点入手:若存在经过其他的边到达v,便不是一定存在。
所以我们只需根据残量网络来做floyd,然后判断是否联通就可以了。
var
n,m,st,en,i,j,k,ans,z:longint;an,x,y:array[1..16900] of longint;
h,d:array[0..1000] of longint;
dis,f:array[1..130,1..130] of longint;
function min(l,r:longint):longint;begin if l<r then exit(l) else exit(r);end;
function max(l,r:longint):longint;begin if l>r then exit(l) else exit(r);end;
function ditch(x,y:longint):longint;
var i,mih,t:longint;
begin
if x=en then exit(y);
mih:=n+1;
for i:=1 to n do
if f[x,i]>0 then begin
if h[x]=h[i]+1 then begin
t:=ditch(i,min(f[x,i],y));
if t>0 then begin
dec(f[x,i],t);
inc(f[i,x],t);
exit(t);
end;
if h[st]>n then exit(0);
end;
mih:=min(mih,h[i]+1);
end;
dec(d[h[x]]);
if d[h[x]]=0 then h[st]:=n+1;
h[x]:=mih;
inc(d[h[x]]);
exit(0);
end;
begin
readln(n,m,st,en);
for i:=1 to m do begin
read(x[i],y[i],z);
f[x[i],y[i]]:=z;
f[y[i],x[i]]:=z;
end;
d[0]:=n;
while h[st]<=n do ans:=ans+ditch(st,maxlongint);
for i:=1 to n do
for j:=1 to n do dis[i,j]:=maxlongint div 3;
for i:=1 to m do begin
if f[x[i],y[i]]<>0 then dis[x[i],y[i]]:=0;
if f[y[i],x[i]]<>0 then dis[y[i],x[i]]:=0;
end;
for i:=1 to n do
for j:=1 to n do
if i<>j then
for k:=1 to n do
if (j<>k)and(k<>i) then begin
dis[j,k]:=min(dis[j,k],dis[j,i]+dis[i,k]);
end;
ans:=0;
for i:=1 to m do begin
if (f[x[i],y[i]]=0)and(dis[x[i],y[i]]<>0) then begin inc(ans);an[ans]:=i;end;
if (f[y[i],x[i]]=0)and(dis[y[i],x[i]]<>0) then begin inc(ans);an[ans]:=i;end;
end;
writeln(ans);
for i:=1 to ans do writeln(an[i]);
end.