poj1637 Sightseeing tour
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 8859 | Accepted: 3728 |
Description
Input
Output
Sample Input
4 5 8 2 1 0 1 3 0 4 1 1 1 5 0 5 4 1 3 4 0 4 2 1 2 2 0 4 4 1 2 1 2 3 0 3 4 0 1 4 1 3 3 1 2 0 2 3 0 3 2 0 3 4 1 2 0 2 3 1 1 2 0 3 2 0
Sample Output
possible impossible impossible possible
Source
混合欧拉回路,用最大流求解。
【建模方法】
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度
之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,
也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。
也就是说,对于每一个点,只要将x 条边改变方向(入>出就是变入,出>入就是变出),就能保证出=入。如果每个点都是出=入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:我该改变哪些边,可以让每个点出=入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入>出的点u,连接边(u, t)、容量为x,对于出>入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0(上限是1,流值不是0就是1)的边反向,就能得到每点入度=出度的欧拉图。
由于是满流,所以每个入>出的点,都有x条边进来,将这些进来的边反向,OK,入=出了。对于出>入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出>入,和t连接的条件是入>出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入=出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。(来自《网络流建模汇总 by Edelweiss》)
15716369 ksq2013 1637 Accepted 932K 32MS G++ 2812B 2016-07-13 13:18:25
#include<cstdio> #include<cstring> #include<iostream> #define INF 0x3f3f3f3f using namespace std; int n,m,s,t,ecnt,first[250],nxt[25000],du[250],res; struct Edge{int u,v,cap,flow;}e[25000]; bool vis[250]; int q[25000],d[250],cur[250],num[250],p[25000]; bool judge() { for(int i=1;i<=n;i++) if(du[i]&1)return false; return true; } void Link(int x,int y,int z) { e[++ecnt].u=x,e[ecnt].v=y,e[ecnt].cap=z,e[ecnt].flow=0; nxt[ecnt]=first[x]; first[x]=ecnt; e[++ecnt].u=y,e[ecnt].v=x,e[ecnt].cap=0,e[ecnt].flow=0; nxt[ecnt]=first[y]; first[y]=ecnt; } void design() { res=0; for(int i=1;i<=n;i++){ if(du[i]<0)Link(i,t,-du[i]/2); if(du[i]>0)Link(s,i,du[i]/2),res+=(du[i]/2); } } void bfs() { memset(vis,false,sizeof(vis)); int head=0,tail=1; q[0]=t;d[t]=0;vis[t]=true; while(head^tail){ int now=q[head++]; for(int i=first[now];i;i=nxt[i]) if(!vis[e[i].u]&&e[i].cap>e[i].flow){ vis[e[i].u]=true; d[e[i].u]=d[now]+1; q[tail++]=e[i].u; } } } int Agument() { int x=t,a=INF; while(x^s){ a=min(a,e[p[x]].cap-e[p[x]].flow); x=e[p[x]].u; } x=t; while(x^s){ e[p[x]].flow+=a; e[p[x]^1].flow-=a; x=e[p[x]].u; } return a; } int ISAP() { int flow=0; bfs(); memset(num,0,sizeof(num)); for(int i=0;i<=n+1;i++)num[d[i]]++; int x=s; for(int i=0;i<=n+1;i++)cur[i]=first[i]; while(d[s]<n+2){ if(!(x^t)){ flow+=Agument(); x=s; } bool advanced=false; for(int i=cur[x];i;i=nxt[i]) if(e[i].cap>e[i].flow&&d[x]==d[e[i].v]+1){ advanced=true; p[e[i].v]=i; cur[x]=i; x=e[i].v; break; } if(!advanced){ int mn=n+1; for(int i=first[x];i;i=nxt[i]) if(e[i].cap>e[i].flow) mn=min(mn,d[e[i].v]); if(--num[d[x]]==0)break; num[d[x]=mn+1]++; cur[x]=first[x]; if(x^s)x=e[p[x]].u; } } return flow; } int main() { int T; scanf("%d",&T); for(;T;T--){ scanf("%d%d",&n,&m); s=0,t=n+1,ecnt=1; memset(d,0,sizeof(d)); memset(p,0,sizeof(p)); memset(nxt,0,sizeof(nxt)); memset(first,0,sizeof(first)); memset(du,0,sizeof(du)); for(int x,y,z,i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); du[x]++,du[y]--; if(!z)Link(x,y,1); } if(!judge()){puts("impossible");continue;} design(); int tmp=ISAP(); if(tmp^res)puts("impossible"); else puts("possible"); } return 0; }