题意:给定一个混合图判断是否存在欧拉回路,<x,y,z>z为1为有向边,z为2为无向边。
比较简单。
黑书上有这道例题,但不知我的书是不是盗版,好几个地方有问题。
概念:
混合图:既有有向边又有无向边。
欧拉回路:图G的一个回路,它恰通过G中每条边一次
对于纯有向图,或纯无向图,判断是否存在欧拉回路都比较简单(判断连通性和出入度),但对于混合图,就需要用到网络流。
首先,将无向边随意定向(转为有向边,方向任意),统计各个点出入度,若出入度之差为奇数,则无论如何将无向边变向,之差仍为奇数,出入边不可能匹配。
如果为偶数,则有可能通过将无向边变向,使出入边一一匹配,可是变向后可能导致其他点的出入边不平衡,所以我们需要总体上达到平衡,这使我们想到网络流的流量平衡条件。我们设如果有流量经过该无向边,则将其变向。
对于出度大于入度的点i,由s向i连容量为差值一半的边,对于入度大于出度的点j,由j向t连容量为差值一半的边,对于其他边,如果是有向边,则删去不保留在网络中,因为其不能再变向,对于无向边,任意定向后,设容量为1,保证只变向一次。
可以看出,如果可以达到满流,与源点连的边,出边必比原入边流量大于差值一半,将由流量边反向,则入度必等于出度。
同理,与汇点连的点可证。
对于中间点,由于流量平衡,又无额外的边,原先的平衡也可以保持。
因此只要能达到满流就能判断为欧拉回路。
构造欧拉回路只需将由流量边反向。
const max=1073741819; type arry=array[0..3000]of longint; var next,sora,flow,pow:arry; d,st,tail,chu,ru:array[0..300]of longint; t,n,m,tt,s,ss,ans,tot:longint; function bfs(s:longint):boolean; var h,r,ne,na,i:longint; begin fillchar(d,sizeof(d),127);fillchar(st,sizeof(st),0); h:=0;r:=1;st[1]:=s;d[s]:=0; repeat inc(h);ne:=st[h]; i:=ne; while next[i]<>0 do begin i:=next[i];na:=sora[i]; if (flow[i]>0)and(d[ne]+1<d[na]) then begin d[na]:=d[ne]+1; inc(r);st[r]:=na end end until h>=r; if d[t]<max then exit(true); exit(false) end; function dfs(x,low:longint):longint; var tmp,na,i:longint; begin if x=t then exit(low); i:=x;dfs:=0; while next[i]<>0 do begin i:=next[i];na:=sora[i]; if (flow[i]>0)and(d[x]+1=d[na]) then begin if flow[i]<low then tmp:=dfs(na,flow[i]) else tmp:=dfs(na,low); if tmp=0 then d[na]:=max; dec(flow[i],tmp);dec(low,tmp);inc(flow[pow[i]],tmp);inc(dfs,tmp); if low=0 then break end end end; procedure dinic; begin while bfs(s) do inc(ans,dfs(s,maxlongint)) end; procedure ori(var x:arry); begin fillchar(x,sizeof(x),0) end; procedure origin; var i:longint; begin ori(flow);ori(sora);ori(next);ori(pow); fillchar(tail,sizeof(tail),0); s:=0;t:=n+1;ss:=t; for i:=s to t do tail[i]:=i end; procedure link(x,y,z:longint); begin inc(ss);next[tail[x]]:=ss;tail[x]:=ss;sora[ss]:=y;flow[ss]:=z; inc(ss);next[tail[y]]:=ss;tail[y]:=ss;sora[ss]:=x;flow[ss]:=0; pow[ss]:=ss-1;pow[ss-1]:=ss end; procedure init; var i,x,y,q:longint; begin readln(n,m); origin; fillchar(chu,sizeof(chu),0);fillchar(ru,sizeof(ru),0); for i:=1 to m do begin readln(x,y,q); if q=1 then begin inc(chu[x]);inc(ru[y]) end else begin inc(chu[x]);inc(ru[y]); link(x,y,1) end end; tot:=0; for i:=1 to n do if abs(chu[i]-ru[i]) and 1=1 then begin writeln('impossible');exit end else begin x:=chu[i]-ru[i]; if x>0 then begin link(s,i,x >>1);tot:=tot+x>>1 end else if x<0 then link(i,t,(-x) >> 1) end; ans:=0; dinic; if ans=tot then writeln('possible') else writeln('impossible') end; begin readln(tt); for tt:=1 to tt do init end.