欧拉回路
无向图:图连通且每个点的度均为偶数
有向图:图连通且每个点入度等于出度
欧拉路径
无向图:图连通且只有两个奇点
有向图:图连通且一个点出度-入度为1,一个点入度-出度为1,其他点均入度等于出度
混合图的欧拉回路
1、随意定向
在混合图中,对于双向边的处理除了拆边之外,还有任意定向。先对全图的双向边进行任意定向,计算出度和入度,如果一个点的出度加入度是奇数的话,那么这个图中没有欧拉回路。虽然随意定向是没有依据的,但是可以使用这样的随机化处理方法,再使用恰当的调整方法构造出解。
2、自调整方法
将其中的一些边的方向调整回来,使所有的点的出度等于入度。但是有一条边的方向改变后,可能会改变一个点的出度的同时改变另一个点的入度,相当于一条边制约着两个点。同时有些点的出度大于入度,迫切希望它的某些点出边转向;而有些点的入度大于出度,迫切希望它的某些入边转向。这两条边虽然需求不同,但是他们之间往往一条边转向就能同时满足二者。
具体步骤:
1、另 x = |入度-出度| / 2,对于不同的点有不同的x值,这个x值代表它们在邻接表中相应调整x条就能让出度等于入度。
2、把图中的点转换为一个二分图,每个点的x值就是它们的点权。
3、源点S向所有出度>入度的点连边,汇点T向所有入度大于出度的点连边,将各自的点权转换为边权。
4、最后将原图中所有暂时定向的无向边加上一个1的容量,方向不变,而有向边不能改变方向,不需连边。
可以发现,从源点S出发的一个单位流将会把一个“无向边”的容量变为0,使得两端的点权各自减1,其实这就是在模拟一次对无向边方向的调整。当把图建好后,依靠最大流性质可以最大可能地无冲突调整边的方向,并最终使得每个点的点容量都达到满流。对那些图中出度等于入度的点做适当分析,它们作为一个“中间点”,由于流平衡性质,不会留下任何流量值,对于那些真正需要调整的点不会带来任何影响。最后检查从源点出发的每条边是否都满流,如果有一条边没有满流,说明有一个点没有调整到入度等于出度,于是整个图不存在欧拉回路。
从一个点出发逛遍所有的路回到出发点,路分为单行路和双行路,这就是一个混合图求欧拉回路的问题。
#include <math.h>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXV = 1010;
const int MAXE = 50010;
const int INF = 0x3f3f3f3f;
int n,m;
int S,T;
int totflow;//满流大小
int dis[MAXV],vis[MAXV],Q[MAXV],h,t;
int out[MAXV],in[MAXV],head[MAXV],cnt;
struct edge{
int u,v,c,next;
}node[MAXE];
void Init(){
cnt = 0, totflow = 0;
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int c){//构建邻接表
node[cnt].v = v;
node[cnt].c = c;
node[cnt].next = head[u];
head[u] = cnt++;
}
int buildflow(){//创建最大流模型
int flag = true;
S = 0, T = n+1;
for(int i=1; i<=n; i++){
if((out[i] + in[i]) & 1) return 0;
else if(out[i] > in[i]){
int c = (out[i] - in[i]) >> 1;
addedge(S, i, c);
addedge(i, S, 0);
totflow += c;
}
else{
int c = in[i] - out[i];
addedge(i, T, c/2);
addedge(T, i, 0);
}
}
return 1;
}
int BFS(){//构建层次图
memset(dis, -1, sizeof(dis));
Q[1] = S, h = 0, t = 1;
dis[S] = 0;
while(h < t){
int u = Q[++h];
for(int i=head[u]; i!=-1; i=node[i].next){
int v = node[i].v, c = node[i].c;
if(dis[v] == -1 && c){
dis[v] = dis[u] + 1;
Q[++t] = v;
if(v == T) return true;
}
}
}
return false;
}
int DFS(int id, int minflow){//Dinic算法过程
if(id == T) return minflow;
int a = 0;
for(int i=head[id]; i!=-1; i=node[i].next){
int v = node[i].v, c = node[i].c;
if(c > 0 && dis[v] == dis[id] + 1
&& (a = DFS(v, min(minflow, c)))){
node[i].c -= a;
node[i^1].c += a;
return a;
}
}
return 0;
}
int Dinic(){
int tmp,ans = 0;
while(BFS()){
while(tmp = DFS(S, INF)) ans += tmp;
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
Init();
scanf("%d%d",&n,&m);
while(m--){
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
out[u]++, in[v]++;
if(u == v) continue;
if(d) continue;
addedge(u, v, 1);
addedge(v, u, 0);
}
int flag = buildflow(), ans = Dinic();
if(!flag) puts("impossible");
else if(ans >= totflow) puts("possible");
else puts("impossible");
}
return 0;
}