题意 给你一个混合图(有向边+无向边),判断是否存在欧拉回路
思路 设d(i) = 出度(i) - 入度(i)。无向边随意定向,先并查集判连通,判di是否都为偶数,不是则不行。
建图,加入s,t两点,对di>0的,s->i建边,最大流量为di/2,对di<0,i->t建边,最大流量为-di/2。把随意定向的无向边,加入图中,最大流量为1.跑最大流,如果最后从s出的边都满流,则有欧拉回路。把那些流量为1的边反向即可加入原图中即可完成无向边的定向。
注意:满流的判断,就用一条边一条边的去看~别瞎用什么别的判别法~
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 202;
const int maxm = 1003;
const int inf = 0x3f3f3f3f;
int n,m;
int g[maxn][maxn][2];
int d[maxn];
struct EdmondsKarp{
//用到外部变量maxn,maxm,具体使用不非得按照模板
int n,m;
int g[maxn][maxn];
int flow[maxn];
int path[maxn];
queue<int> q;
void init(int nn=0)
{
n = nn;
memset(g,0,sizeof(g));
memset(flow,0,sizeof(flow));
memset(path,-1,sizeof(path));
}
void addOne(int u,int v,int yuan)
{
g[u][v] += yuan;
m += 2;
}
int bfs(int s,int t)
{
int i;
memset(path,-1,sizeof(path));
flow[s] = inf;
//如果不加这句话,bfs内部就要一共三个判断
path[s] = s;
q.push(s);
while(q.size()>0)
{
int tmp = q.front();
q.pop();
//这里i从0开始还是1开始,视情况而定
for(i=0;i<n;i++)
{
if(g[tmp][i]>0 && path[i]==-1)
{
flow[i] = min(g[tmp][i],flow[tmp]);
path[i] = tmp;
q.push(i);
if(i==t)
{
break;
}
}
}
if(path[t] != -1)
break;
}
while(q.size()>0)
q.pop();
if(path[t] == -1)
return 0;
else
return flow[t];
}
int go(int s,int t)
{
int ret = 0;
while(bfs(s,t))
{
int now = path[t];
int pre = t;
ret += flow[t];
while(pre != s)
{
g[now][pre] -= flow[t];
g[pre][now] += flow[t];
pre = now;
now = path[now];
}
}
return ret;
}
}edk;
int fa[maxn];
int find(int x)
{
if(fa[x] == x)
return x;
else
return fa[x] = find(fa[x]);
}
void unin(int x,int y)
{
x = find(x);
y = find(y);
if(x==y)
return;
fa[x] = y;
}
void addEdge()
{
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
fa[i] = i;
for(int i=0;i<m;i++)
{
int u,v,b;
scanf("%d%d%d",&u,&v,&b);
if(b==1)
g[u][v][1]++;
else
g[u][v][0]++;
//出度减入度
d[u]++;
d[v]--;
unin(u,v);
}
}
void create()
{
edk.init(n+2);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(g[i][j][0])
edk.addOne(i,j,g[i][j][0]);
}
}
for(int i=1;i<=n;i++)
{
if(d[i] > 0)
{
edk.addOne(0,i,d[i]/2);
}
else if(d[i] < 0)
{
edk.addOne(i,n+1,-d[i]/2);
}
}
}
bool judge()
{
for(int i=2;i<=n;i++)
{
if(find(i) != find(i-1))
return false;
}
for(int i=1;i<=n;i++)
{
if(d[i] % 2 != 0)
return false;
}
return 1;
}
int main()
{
int T;
cin>>T;
while(T--)
{
addEdge();
if(judge() == 0)
{
puts("impossible");
continue;
}
create();
edk.go(0,n+1);
int sum = 0;
int i = 1;
for(i=1;i<=n;i++)
{
if(d[i] > 0)
{
if(edk.g[0][i] > 0)
break;
}
}
if(i == n+1)
puts("possible");
else
puts("impossible");
}
return 0;
}