判断混合图欧拉回路 poj 1637

题意:给定一个混合图判断是否存在欧拉回路,<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.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值