Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 9250 | Accepted: 3908 |
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
大意:欧拉混合图,有单向边也有双向边问你存不存在一个欧拉图。
嗯,我们都知道无向欧拉图的度数为偶数,且联通。对于有向的欧拉图便是入度等于出度了。
我们现在的问题其实就是在这些无向边中我应该怎么来选择方向,使得这个图变成一个欧拉图。
建模方法:
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以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连接的点,自然早在开始就已经满足入=出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int MAXN=200+10;
int tu[MAXN][MAXN];
int n,m;
int s,e;
int in[MAXN],out[MAXN];
int pre[MAXN],flow[MAXN];
int EK()
{
int i;
flow[s]=inf;
memset(pre,-1,sizeof(pre));
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();
if(u==e)break;
q.pop();
for(i=1; i<=e; ++i)
{
if(pre[i]==-1&&tu[u][i])
{
pre[i]=u;
flow[i]=min(flow[u],tu[u][i]);
q.push(i);
}
}
}
if(pre[e]==-1)return 0;
else return flow[e];
}
int get_maxflow()
{
int max_flow=0;
int flow=EK();
while(flow)
{
max_flow+=flow;
int u=pre[e],v=e;
while(u!=-1)
{
tu[u][v]-=flow;
tu[v][u]+=flow;
v=u;
u=pre[v];
}
flow=EK();
}
return max_flow;
}
int main()
{
int t;
int i;
scanf("%d",&t);
while(t--)
{
memset(tu,0,sizeof(tu));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
scanf("%d%d",&n,&m);
int u,v,d;
s=0;
e=n+1;
while(m--)
{
scanf("%d%d%d",&u,&v,&d);
out[u]++;
in[v]++;
if(!d)
{
tu[u][v]++;
}
}
int ans;
int sum1=0,sum2=0;
for(i=1; i<=n; ++i)
{
d=abs(in[i]-out[i]);
if(d%2)break;
else
{
d/=2;
if(in[i]>out[i])
{
tu[i][e]=d;
sum1+=d;
}
else
{
tu[0][i]=d;
sum2+=d;
}
}
}
ans=max(sum1,sum2);
if(i<=n)puts("impossible");
else
{
if(ans==get_maxflow())puts("possible");
else puts("impossible");
}
}
return 0;
}