分析
混合图欧拉回路问题。
一个有向图有欧拉回路当且仅当图连通并且对于每个点,入度(=)出度。
入度和出度相等可以联想到(我也不知道是怎么联想到的)网络流除了源汇点均满足入流(=)出流。于是可以考虑先将无向边随意定向后,通过网络流来调整无向边的方向以达到每个点的入度和出度相等的目的。
建图方法如下:
-
若(outdeg[x]>indeg[x]),则从(S)向(x)连一条容量为(frac{outdeg[x]-indeg[x]}{2})的边。
-
若(outdeg[x]<indeg[x]),则从(x)向(T)连一条容量为(frac{indeg[x]-outdeg[x]}{2})的边。
-
将每一条你定向的有向边令其容量为(1)加入到网络中。
这样一条增广路的意义就是将路径上的边全部取反,然后将第一个结点的入度(++),出度(--),将最后一个结点的入度(--),出度(++)。
怎么判无解?
把所有边都看作无向边,那么如果存在一个节点的度数为奇数,直接输出impossible
即可。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <queue>
#define rin(i,a,b) for(register int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[x];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=205;
const int MAXM=1005;
int n,m,S,T,maxflow,ecnt,head[MAXN];
int indeg[MAXN],outdeg[MAXN],dep[MAXN],cur[MAXN];
std::queue<int> q;
struct Edge{
int to,nxt,cap;
}e[MAXM*2+MAXN*2];
inline void add_edge(int bg,int ed,int ca){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
e[ecnt].cap=ca;
head[bg]=ecnt;
}
inline bool bfs(){
memset(dep,0,sizeof dep);
rin(i,1,T) cur[i]=head[i];
while(!q.empty()) q.pop();
q.push(S);
dep[S]=1;
while(!q.empty()){
int x=q.front();q.pop();
trav(i,x){
int ver=e[i].to;
if(dep[ver]||!e[i].cap) continue;
dep[ver]=dep[x]+1;
q.push(ver);
}
}
return dep[T]>0;
}
int dfs(int x,int pref){
if(x==T||!pref) return pref;
int flow=0,temp;
for(int &i=cur[x];i;i=e[i].nxt){
int ver=e[i].to;
if(dep[ver]==dep[x]+1&&(temp=dfs(ver,std::min(pref,e[i].cap)))){
e[i].cap-=temp;
e[i^1].cap+=temp;
flow+=temp;
pref-=temp;
if(!pref) return flow;
}
}
return flow;
}
inline void dinic(){
while(bfs()) maxflow+=dfs(S,1e9);
}
int main(){
int TT=read();
while(TT--){
ecnt=1;memset(head,0,sizeof head);
memset(indeg,0,sizeof indeg);
memset(outdeg,0,sizeof outdeg);
maxflow=0;
n=read(),m=read();S=n+1,T=S+1;
rin(i,1,m){
int u=read(),v=read(),typ=read();
if(!typ){
add_edge(u,v,1);
add_edge(v,u,0);
outdeg[u]++;
indeg[v]++;
}
else{
outdeg[u]++;
indeg[v]++;
}
}
bool flag=0;
rin(i,1,n){
flag|=((outdeg[i]+indeg[i])&1);
}
if(flag){
printf("impossible
");
continue;
}
int temp=0;
rin(i,1,n){
if(outdeg[i]>indeg[i]){
add_edge(S,i,(outdeg[i]-indeg[i])/2);
add_edge(i,S,0);
temp+=(outdeg[i]-indeg[i])/2;
}
else if(outdeg[i]<indeg[i]){
add_edge(i,T,(indeg[i]-outdeg[i])/2);
add_edge(T,i,0);
}
}
dinic();
if(maxflow<temp) printf("impossible
");
else printf("possible
");
}
return 0;
}