poj 1637 Sightseeing tour
给定一张m个点s条边混合图(有向边和无向边),求是否存在欧拉回路。
1<=m<=200.1<=s<=1000.
混合图欧拉回路需要借助最大流。
有向图欧拉回路的充要条件:图联通且每个点入度等于出度。所以转化为有向图,将每条无向边任意定向,统计入出度。考虑将一条有向边反向会让点的入出度差的绝对值变化2,即若存在某点入出度之差为奇数,则不存在欧拉回路。
如果入出度之差为偶数,则建图网络流判断。
对于每条无向边,按刚才定的向连一条容量为1的边。
源点向所有出度大于入度的点连一条容量为入出度差绝对值除以2的边。
所有入度大于出度的点向汇点连一条容量为入出度差绝对值除以2的边。
跑最大流,若满流则存在欧拉回路,否则不存在。
若存在,将所有流量不为0的边反向,所有点的入出度差均变为0,即可得到一张存在欧拉回路的有向图。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int dian=205; 8 const int bian=3005; 9 const int INF=0x3f3f3f3f; 10 int h[dian],ver[bian],val[bian],nxt[bian],ch[dian],cr[dian]; 11 int ru[dian],chu[dian]; 12 int cas,n,m,tot,aa,bb,ok; 13 int S,T; 14 int aabs(int a){ 15 if(a<0) 16 return -a; 17 return a; 18 } 19 void add(int a,int b,int c){ 20 tot++;ver[tot]=b;val[tot]=c;nxt[tot]=h[a];h[a]=tot; 21 tot++;ver[tot]=a;val[tot]=0;nxt[tot]=h[b];h[b]=tot; 22 } 23 bool tell(){ 24 memset(ch,-1,sizeof(ch)); 25 queue<int>q; 26 q.push(S); 27 ch[S]=0; 28 while(!q.empty()){ 29 int t=q.front(); 30 q.pop(); 31 for(int i=h[t];i;i=nxt[i]) 32 if(ch[ver[i]]==-1&&val[i]){ 33 ch[ver[i]]=ch[t]+1; 34 q.push(ver[i]); 35 } 36 } 37 return ch[T]!=-1; 38 } 39 int zeng(int a,int b){ 40 if(a==T) 41 return b; 42 int r=0; 43 for(int i=cr[a];i&&b>r;i=nxt[i]) 44 if(ch[ver[i]]==ch[a]+1&&val[i]){ 45 int t=zeng(ver[i],min(b-r,val[i])); 46 val[i]-=t,r+=t,val[i^1]+=t; 47 if(val[i]) 48 cr[a]=i; 49 } 50 if(!r) 51 ch[a]=-1; 52 return r; 53 } 54 int dinic(){ 55 int r=0,t; 56 while(tell()){ 57 for(int i=1;i<=n+2;i++) 58 cr[i]=h[i]; 59 while(t=zeng(S,INF)) 60 r+=t; 61 } 62 return r; 63 } 64 int main(){ 65 scanf("%d",&cas); 66 while(cas--){ 67 memset(h,0,sizeof(h)); 68 memset(nxt,0,sizeof(nxt)); 69 memset(ru,0,sizeof(ru)); 70 memset(chu,0,sizeof(chu)); 71 tot=1; 72 scanf("%d%d",&n,&m); 73 S=n+1,T=n+2; 74 for(int i=1;i<=m;i++){ 75 scanf("%d%d%d",&aa,&bb,&ok); 76 chu[aa]++; 77 ru[bb]++; 78 if(!ok) 79 add(aa,bb,1); 80 } 81 int lala=0; 82 for(int i=1;i<=n;i++) 83 if(aabs(ru[i]-chu[i])&1){ 84 lala=1; 85 break; 86 } 87 if(lala){ 88 printf("impossible\n"); 89 continue; 90 } 91 int ans=0; 92 for(int i=1;i<=n;i++){ 93 if(ru[i]==chu[i]) 94 continue; 95 if(ru[i]>chu[i]) 96 add(i,T,(ru[i]-chu[i])/2); 97 else{ 98 add(S,i,(chu[i]-ru[i])/2); 99 ans+=(chu[i]-ru[i])/2; 100 } 101 } 102 if(dinic()==ans) 103 printf("possible\n"); 104 else 105 printf("impossible\n"); 106 } 107 return 0; 108 }
PS:代码忘了判图连通,不知道题目有没有保证,poj数据过了,懒得加了就这样吧。