hdu 1956 Sightseeing tour(混合图欧拉回路)

来源:互联网 发布:淘宝网名昵称大全2016 编辑:程序博客网 时间:2024/06/10 06:03
Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 357    Accepted Submission(s): 158


Problem Description
The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once. The bus should also start and end at the same junction. As in any city, the streets are either one-way or two-way, traffic rules that must be obeyed by the tour bus. Help the executive board and determine if it’s possible to construct a sightseeing tour under these constraints.
 

Input
On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two positive integers m and s, 1<=m<=200, 1<=s<=1000 being the number of junctions and streets, respectively. The following s lines contain the streets. Each street is described with three integers, xi, yi, and di, 1<=xi,yi<=m, 0<=di<=1, where xi and yi are the junctions connected by a street. If di=1, then the street is a one-way street (going from xi to yi), otherwise it’s a two-way street. You may assume that there exists a junction from where all other junctions can be reached.
 

Output
For each scenario, output one line containing the text “possible” or “impossible”, whether or not it’s possible to construct a sightseeing tour.
 

Sample Input
45 82 1 01 3 04 1 11 5 05 4 13 4 04 2 12 2 04 41 2 12 3 03 4 01 4 13 31 2 02 3 03 2 03 41 2 02 3 11 2 03 2 0
 

Sample Output
possibleimpossibleimpossiblepossible
来自http://www.cnblogs.com/ylfdrib/archive/2010/08/21/1805201.html 

一个无向图是欧拉图,当且仅当该图所有顶点度数都是偶数。

一个有向图是欧拉图,当且仅当该图所有顶点度数都是0。

有向图存在欧拉回路的充要条件:基图(把所有有向边变成无向边以后得到的图)连通,且每个点的出度等于入度。

所以求混合图的关键是:判断能否存在一个定向,使得每个节点的入度等于出度。

在原图中,首先给每条无向边任意定向,构成一个有向图,计算每个点的度deg,入度为正,出度为负,如果某个点的deg为奇数,显然不存在欧拉回路。由于原来的有向边,不能更改方向,无用,删了,对原图中的无向边定向后构成的有向图,如果点 i 到j 有一条弧,弧< i ,  j >容量加1(i 到 j 有多条边的时候,即有重边,可以一条边,多容量代替) 增加源点S,汇点T,对于每个点 i ,如果deg < 0,即出度大于入度,从S引一条弧到 i ,容量为(- deg ) / 2;如果deg > 0, 即入度大于出度,从 i 引一条弧到 T,容量为 deg / 2,如果deg = 0,就不用建边了。求新网络的最大流。如果从S出发的所有弧满载,则欧拉回路存在,把所有的有流的弧全部反向(如果某条边容量大于1,流量为几,反向几条边就可以了),把原图中的有向边再重新加入,就得到了一个有向欧拉回路。

满载是为了流量平衡,为了每个顶点的入度和出度相等。

为什么把有流边反向,就能得到一个欧拉回路呢?

想一想:如果有流边<u, v>反向,则deg[u]就增加了2, deg[v]减少了2, 这就是为什么开始加弧的时候为什么deg要除以2的原因了,每增加一个流量,就有一条起点到终点的路径,把路径上的所有点都反向,则起点的度增加了2, 终点的度减少了2, 中间点度数不变,而起点如果有这条流量,就代表他的出度大,入度小,需要更改临边来使得最终出度等于入度,最大流的这个性质正好满足,如果所有S到v的弧满流了,那么经过上面的操作,v点的出度必然等于入度,如果所有从S出发的弧都满流了,那么就找到以一种定向方式使得原图得到了一个有向欧拉回路。

#include<iostream>#include<stdio.h>using namespace std;#include<queue>#include<string.h>#include<math.h>#include<algorithm>#define MS(a,b) memset(a,b,sizeof(a))#define INF 0x7fffffffint head[50000],dis[3000],f,n,m,in[3000],out[3000];struct node{    int to,next,w;}edge[50000];void add(int u,int v,int w){  edge[f].to=v;  edge[f].next=head[u];  edge[f].w=w;  head[u]=f++;  edge[f].to=u;  edge[f].next=head[v];  edge[f].w=0;  head[v]=f++;}int bfs(){  int i,x,v;  MS(dis,0);  dis[0]=1;  queue<int>q;  q.push(0);  while(!q.empty())  {    x=q.front();    q.pop();    for(i=head[x];i!=-1;i=edge[i].next)    {  v=edge[i].to;      if(edge[i].w&&dis[v]==0)      {          dis[v]=dis[x]+1;       if(v==n+1)return 1;          q.push(v);      }    }  }  return 0;}int dfs(int s,int cur_flow){    int i,v,tmp,dt=cur_flow;    if(s==n+1)return cur_flow;    for(i=head[s];i!=-1;i=edge[i].next)    {       v=edge[i].to;       if(edge[i].w&&dis[s]==dis[v]-1)       {         int flow=dfs(v,min(dt,edge[i].w));               edge[i].w-=flow;               edge[i^1].w+=flow;               dt-=flow;       }    }    return cur_flow-dt;}int dinic(){  int ans=0;  while(bfs())    ans+=dfs(0,INF);  return ans;}int main(){    int t,i,a,b,h,sign,g,sum,ans;    cin>>t;    while(t--)    {   sum=sign=f=0;        cin>>n>>m;        MS(head,-1);        MS(in,0);        MS(out,0);       for(i=0;i<m;i++)       {           cin>>a>>b>>h;           in[b]++,out[a]++;           if(h==0)            add(a,b,1);       }      for(i=1;i<=n;i++)      {         int k=abs(in[i]-out[i]);          if(k&1)              sign=1;//计算每个点的度deg,入度为正,出度为负,如果某个点的deg为奇数,显然不存在欧拉回路         g=in[i]-out[i];              if(g>0)                 add(i,n+1,g/2);//如果deg > 0, 即入度大于出度,从 i 引一条弧到 T,容量为 deg / 2              else if(g<0)              {                 add(0,i,-g/2);//如果deg < 0,即出度大于入度,从S引一条弧到 i ,容量为(- deg ) / 2;                 sum=sum-g/2;              }      }      if(sign)cout<<"impossible\n";      else      {          ans=dinic();          if(sum==ans)//如果从S出发的所有弧满载,则欧拉回路存在            cout<<"possible\n";          else cout<<"impossible\n";      }    }    return 0;}



0 0
原创粉丝点击