POJ 1637 浅谈混合图欧拉回路网络流建模
2017-07-12 16:15
363 查看
世界真的很大
欧拉是个厉害的人
从数论到图论,欧拉函数到欧拉回路
欧拉回路好像是他在意大利的什么地方有7个岛搞出来的
但是这道题的解法和欧拉关系不大了,是网络流
所以说网络流也是一个神奇东西
先看一下题:
description:
给定一张有向边和无向边构成的混合图。求给其中的无向边给定方向是否能使其含有一条欧拉回路
input
一个数字T表示数据组数 每组数据第一行包含2个整数n,m,表示点数和边数 接下来m行,每行包括3个整数u,v,mrk,表示u,v之间有一条边,0是无向边,1是有向边
output
每组数据输出impossible或possible表示数据有无解
思路比较不好想
有大佬有更厉害的做法
但我就只知道听了老师的一知半解地yy了
首先要明白欧拉回路的充要条件,即充分,必要,就是每个点的出度等于入度
通过给出的有向边,我们能知道每个点的出入度情况,不妨把所有无向边都假设为有向边,统计一次出入度
必然有某些点的出度不等于入度的情况
可以通过更改某些无向边的方向来调整,如果使一条无向边的方向反过来,即某个点的出度会+1,入度会-1,所以如果统计下来某个点的出入度之差是奇数,那就不可能调整为出入度相等了,就肯定没有欧拉回路了
在所有点的出入度之差都为偶数的情况下,如果一个点的入度大于出度,就好像有些边进来了,却没有出去,即这个点需要流出边,流出边的数量正好是出入度之差的一半
同理有些点的出度大于入度,相当于流入的边不够流出,就需要流入,需要流入的边的数量正好是出入度之差的一半
初步建模就完成了,源点向所有入度大于出度的点连边,权值为其出入度之差的一半,代表有这么多的边需要流出
所有出度大于入度的点向汇点连边,权值为其出入度之差的一半,相当于有这么多的边需要流入
那么现在需要考虑进一步的调整问题了
对于一条本来是无向边的边(u,v),我们强行假设了这是一条有向边,从u到v,那换句话说只要(u,v)反向,就能使u的出度减少,入度增加;v的出度增加,入度减少。
换个思路吧
也就是说,只要存在(u,v)这条边,就有办法 调整 u和v的出入度关系,如果此时v的入度大于出度,即v与S建了边,有一定流量需要流出,因为(u,v)的存在,v的流量可以通过(u,v)反向的方式流到u,使u的入度增加,如果此时u是出度大于入度的话,正好是一种调整方式
进一步的建边思路就出来了
如果一开始假设无向边(u,v)是从u到v,那么就建一条v到u流量为1的边,表示v需要流出的流量可以通过边反向的方式流到u
接下来跑一遍dinic
如果求出的最大流是满流,就是所有需要流出的边都找到了流入的点,每个点的出度等于入度,就说明有一种方案了
完整代码:
#include<stdio.h> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int INF=0x3f3f3f3f; struct edge { int v,last,w; }ed[100010]; queue <int> state; int head[100010],dis[100010],in[100010],ou[100010]; int num=1,n,m,S,T,tot,ans,flag,Tt; void init() { num=1,S=0,T=n+1,tot=0,ans=0,flag=0; memset(head,0,sizeof(head)); memset(in,0,sizeof(in)); memset(ou,0,sizeof(ou)); } void add(int u,int v,int w) { num++; ed[num].v=v; ed[num].w=w; ed[num].last=head[u]; head[u]=num; } bool bfs() { while(state.size()) state.pop(); memset(dis,-1,sizeof(dis)); dis[S]=0; state.push(S); while(!state.empty()) { int u=state.front(); state.pop(); for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(dis[v]==-1&&ed[i].w>0) { dis[v]=dis[u]+1; state.push(v); } } } if(dis[T]==-1) return 0; return 1; } int dfs(int u,int low) { if(u==T || low==0) return low; int a=0; for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(ed[i].w>0&&dis[v]==dis[u]+1) { int tmp=dfs(v,min(low,ed[i].w)); ed[i].w-=tmp; ed[i^1].w+=tmp; a+=tmp,low-=tmp; if(low==0) return a; } } if(low) dis[u]=-1; return a; } int main() { scanf("%d",&Tt); while(Tt--) { scanf("%d%d",&n,&m); init(); for(int i=1;i<=m;i++) { int u,v,mrk; scanf("%d%d%d",&u,&v,&mrk); in[v]++,ou[u]++; if(!mrk) { add(v,u,1); add(u,v,0); } } for(int i=1;i<=n;i++) if(abs(in[i]-ou[i])&1) { flag=1; break ; } else if(in[i]>ou[i]) { add(S,i,(in[i]-ou[i])>>1); add(i,S,0);tot+=(in[i]-ou[i])/2; } else if(in[i]<ou[i]) { add(i,T,(ou[i]-in[i])>>1); add(T,i,0); } if(flag) { printf("impossible\n"); continue ; } while(bfs()) ans+=dfs(S,INF); if(ans!=tot) printf("impossible\n"); else printf("possible\n"); } return 0; } /* Whoso pulleth out this sword from this stone and anvil is duly born King of all England */
嗯,就是这样
相关文章推荐
- POJ 1637 【网络流建模汇总】混合图欧拉回路
- POJ 1637 Sightseeing tour (网络流解决混合图欧拉回路问题)
- poj 1637 混合欧拉回路 网络流 dinic 以及sap 算法
- POJ-1637 Sightseeing tour(通过网络流判定混合图的欧拉回路)
- POJ1637 Sightseeing tour (混合图欧拉回路)(网络流)
- POJ 1637 网络流判混合欧拉回路 解题报告
- POJ-1637 混合图欧拉回路-网络流求解
- poj 1637 (浅谈最大流在解决混合图欧拉回路中的应用)
- poj1637 混合图欧拉回路的求解 网络流
- POJ 1637 混合图的欧拉回路 网络流
- poj1637 Sightseeing tour 网络流 混合图的欧拉回路
- poj 1637 Sightseeing tour 【网络流 求解混合欧拉回路是否存在】
- POJ 1637 Sightseeing tour(混合欧拉回路,网络流)
- poj 1637(混合图求欧拉回路)
- POJ 1637:Sightseeing tour 混合图欧拉回路
- poj 1637 求混合图的欧拉回路
- poj 1637判定混合图欧拉回路 uva10735 混合欧拉回路+路径输出
- POJ 1637 Sightseeing tour (混合图的欧拉回路)
- poj 1637 混合图欧拉回路 学习笔记
- POJ 1637 Sightseeing tour 混合图欧拉回路存在性判断