题目大意:
给你m个点,有s条边,这s条边有的是有向边(di = 1),有的是无向边(di = 0),问你这个图是否存在欧拉回路。
解题思路:
我是看着这个题解写出来这道题目的。链接在这里
把这个混合图先当作是有向图,每个输入xi,yi,di不管di为0或1,均当作是从xi到yi的有向边(无向边可任意设置方向),然后记录入度和出度的差值,如果差值为奇数则必然不可能存在欧拉回路。剩下的部分可以利用最大流来判断。
如果某个点的入度比出度大,则从源点s引一条边与这个点相连通,容量为差值的一半
如果某个点的出度比入度大,则从这个点引一条边与汇点t相联通,容量也为差值的一半
遍历每个点对<i,j>如果他们相联通,则引一条从j到i的边,容量为这条边重复的次数。
然后判断最大流与入度比出度大的这部分差值的和是否相等。不相等则impossible,相等则possible
这么写的原因是因为一开始所写的判断图是把无向边当作一条有向边来进行判断了。那么判断原本的图就需要把这部分给补偿回去。
我们知道,如果一个有向图想要有欧拉回路,那么它需要每个点的入度与出度相同。
也就是说对于入度比出度大的点,相当于“提供水流”的这种节点。
对于入度比出度大的点,相当于“排除水流”的这种节点。
而补偿一来一回,所以容量为差值的一半。
这道题其实很像是电网模型= =
讲到这里,只能惊呼,“神奇的网络流啊!”
代码:
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
typedef struct node{
int v, cap, nxt;
node(int a = 0, int b = 0, int c = 0){
v = a; cap = b; nxt = c;
}
}Edge;
const int maxn = 200 + 5;
const int INF = 0x3f3f3f3f;
int m, s, t, tot;
Edge edge[50005];
int head[maxn], deg[maxn], dis[maxn], mp[maxn][maxn];
inline int Min(int a, int b){
return (a < b ? a : b);
}
void add(int u, int v, int cap){
edge[tot] = Edge(v, cap, head[u]);
head[u] = tot++;
edge[tot] = Edge(u, 0, head[v]);
head[v] = tot++;
}
int bfs(){
queue<int> q;
while(!q.empty()) q.pop();
memset(dis, 0, sizeof(dis));
q.push(s); dis[s] = 1;
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(e.cap && dis[e.v] == 0){
dis[e.v] = dis[x] + 1;
q.push(e.v);
}
}
}
return dis[t];
}
int dfs(int x, int f){
if(x == t) return f;
int sum = 0;
for(int i = head[x]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(e.cap && dis[e.v] == dis[x] + 1){
int ret = dfs(e.v, Min(e.cap, f));
sum += ret; f -= ret;
e.cap -= ret; edge[i^1].cap += ret;
}
}
return sum;
}
int dinic(int sum){
int ret = 0;
tot = 0;
s = 0; t = m + 1;
memset(head, -1, sizeof(head));
for(int i = 1; i <= m; ++i){
if(deg[i] > 0) add(s, i, deg[i] >> 1);
else if(deg[i] < 0) add(i, t, (-deg[i]) >> 1);
}
for(int i = 1; i <= m; ++i){
for(int j = 1; j <= m; ++j){
if(mp[i][j]) add(j, i, mp[i][j]);
}
}
while(bfs()) ret += dfs(s, INF);
return (ret == sum);
}
int main(){
int a, b, c, t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &m, &s);
memset(mp, 0, sizeof(mp));
memset(deg, 0, sizeof(deg));
for(int i = 0; i < s; ++i){
scanf("%d%d%d", &a, &b, &c);
--deg[a]; ++deg[b];
if(c == 0) ++mp[a][b];
}
int flag = 1, sum = 0;
for(int i = 1; flag && i <= m; ++i){
if(deg[i] > 0) sum += deg[i] >> 1;
if(deg[i] & 1) flag = 0;
}
if(flag) flag = dinic(sum);
if(flag) puts("possible");
else puts("impossible");
}
return 0;
}