POJ 1637 Sightseeing tour 建图+网络流

题意:

  给定一个混合图,所谓混合图就是图中既有单向边也有双向边,现在求这样的图是否存在欧拉回路。

分析:

  存在欧拉回路的有向图,必须满足[入度==出度],现在,有些边已经被定向,所以我们直接记录度数即可,对于无向边呢?

  对于这样的边,我们只需要先随便定向,然后记录出入度。(这些边只用来计算出入度,不用于网络流建图)

  然后我们开始建图。现在极有可能有些点是不满足[入度==出度]的,所以我们要通过一些变向操作,使得图中所有点满足判定。

  如果一个点入度和出度的奇偶性不同,那整张图一定是不合法的。因为改变一条边的方向对端点的入度和出度是同时影响的,且是反向的,比如入度加一出度减一,或者出度加一入度减一,因此无论如何,那样的点都不可能满足判定条件的;

  随后,我们对于:

  所有入度>出度的点,从超级源点连一条容量为(入度-出度)/2的边;

  所有出度>入度的点,向超级汇点连一条容量为(出度-入度)/2的边;

  这样,一单位流量的需求,意味着有这么多边需要变向来使图满足判定条件。所以那些边可以变向,我们就使它的贡献为1 。

  所以,对于我们曾随便定向的那些无向边,我们在网络流建图中,向它们相反方向建一条流量为1的边(与我们随便定的向相反)。

  之后检验整张图与源点汇点连得边是否满流,满流则possible,不满则impossible。

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #define ms(a,x) memset(a,x,sizeof(a))
 8 using namespace std;
 9 const int inf=0x3f3f3f3f;
10 const int N=1005;
11 struct edge{int x,y,d;}w[N];
12 struct node{int y,z,nxt;}e[N*2];
13 int in[N],ot[N],S,T,q[N],h[N],c=1;
14 int n,m,sm=0,tot=0,d[N],k,cas,flg;
15 void add(int x,int y,int z){
16     e[++c]=(node){y,z,h[x]};h[x]=c;
17     e[++c]=(node){x,0,h[y]};h[y]=c;
18 } bool bfs(){
19     int f=1,t=0;ms(d,-1);
20     q[++t]=S;d[S]=0;
21     while(f<=t){
22         int x=q[f++];
23         for(int i=h[x],y;i;i=e[i].nxt)
24         if(d[y=e[i].y]==-1&&e[i].z)
25         d[y]=d[x]+1,q[++t]=y;
26     } return (d[T]!=-1);
27 } int dfs(int x,int f){
28     if(x==T) return f;int w,tmp=0;
29     for(int i=h[x],y;i;i=e[i].nxt)
30     if(d[y=e[i].y]==d[x]+1&&e[i].z){
31         w=dfs(y,min(e[i].z,f-tmp));
32         if(!w) d[y]=-1;
33         e[i].z-=w;e[i^1].z+=w;
34         tmp+=w;if(tmp==f) return f;
35     } return tmp;
36 } void dinic(){
37     while(bfs()) tot+=dfs(S,inf);
38 } int main(){
39     scanf("%d",&cas);while(cas--){
40         scanf("%d%d",&n,&m);flg=0;
41         ms(in,0);ms(ot,0);ms(h,0);
42         c=1;S=0,T=n+1;sm=0,tot=0;
43         for(int i=1;i<=m;i++)
44         scanf("%d%d%d",&w[i].x,&w[i].y,&w[i].d),
45         in[w[i].y]++,ot[w[i].x]++;
46         for(int i=1;i<=n;i++){
47             if((in[i]&1)^(ot[i]&1))
48             {flg=1;break;}
49             if(in[i]>ot[i]) //sm+=in[i]-ot[i],
50             add(S,i,(in[i]-ot[i])/2);
51             if(in[i]<ot[i]) sm+=ot[i]-in[i],
52             add(i,T,(ot[i]-in[i])/2); 
53         } if(flg){puts("impossible");continue;}
54         for(int i=1;i<=m;i++)
55         if(!w[i].d) add(w[i].y,w[i].x,1);
56         dinic();sm>>=1;
57         if(tot==sm) puts("possible");
58         else puts("impossible");
59     } return 0;
60 }
最大流

 

  

posted @ 2019-01-09 08:07  杜宇一声  阅读(129)  评论(0编辑  收藏  举报