HDU - 3472 HS BDC (Dinic算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3472

判断混合欧拉路径,可以转化为判断混合欧拉回路。欧拉路存在要求度数全部为0,或者仅有2个度数为奇数。若有2个奇数度,则添加一条不定向边将度数变为偶数。
然后判断能否通过调整不定向边的方向使得全部度数为0,用dinic算法计算最大流,自己外加一个起点s和终点t,起点s指向所有度数大于0的点(即出度大于入度),让所有度数小于0的点指向t,权值都是设为度数绝对值的一半,如果从s出发的所有边都满流说明构成了欧拉回路。因为根据残留网络的反向路径,度数大于0的点在满流后度数变为0。度数小于0的点也同理。

参考:https://www.iteye.com/blog/yzmduncan-1149049

注意:首先判断是否为连通图。

#include
#include
#include
#include
#include
#include
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 2010;
struct node {
	int to, cap, nxt;
};
node e[N];
int head[N], cur[N], dis[N], cnt, du[N], g[N][N];
int s = 30, t = 31, toCheck[N], has[30];
int fa[N];
int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y)fa[y] = x;
}
void addedge(int u, int v, int w) {
	e[cnt].to = v;
	e[cnt].cap = w;
	e[cnt].nxt = head[u];
	head[u] = cnt++;
}
bool bfs() {
	memset(dis, 0, sizeof(dis));
	dis[s] = 1;
	queue<int>Q;
	Q.push(s);
	while (!Q.empty()){
		int u = Q.front(); Q.pop();
		if (u == t)return true;
		for (int i = head[u]; i != -1; i = e[i].nxt) {
			int v = e[i].to;
			if (!dis[v] && e[i].cap) {
				dis[v] = dis[u] + 1;
				Q.push(v);
			}
		}
	}
	return false;
}
int dfs(int u,int flow) {
	if (u == t)return flow;
	int res = 0;
	for (int& i = cur[u]; i != -1; i = e[i].nxt) {
		int v = e[i].to;
		if (dis[v] == dis[u] + 1 && e[i].cap) {
			int f = dfs(v, min(flow - res, e[i].cap));
			if (f) {
				e[i].cap -= f;
				e[i ^ 1].cap += f;
				res += f;
				if (res == flow)break;
			}
		}
	}
	if (!res)dis[u] = 0;
	return res;
}
int dinic() {
	int maxflow = 0;
	while (bfs()) {
		memcpy(cur, head, sizeof(cur));
		maxflow += dfs(s, inf);
	}
	return maxflow;
}
string str;
int main(void) {
	int T, kase = 0; scanf("%d", &T);
	while (T--) {
		int n, f; scanf("%d", &n);
		for (int i = 1; i <= 26; i++) {
			fa[i] = i; has[i] = 0;
		}
		memset(head, -1, sizeof(head));
		memset(du, 0, sizeof(du));
		memset(g, 0, sizeof(g));
		cnt = 0;
		while (n--) {
			cin >> str;
			int u = str[0] - 'a' + 1;
			int v = str.back() - 'a' + 1;
			du[u]++; du[v]--;
			scanf("%d", &f);
			if (f) g[u][v]++;
			merge(u, v);
			has[u] = has[v] = 1;
		}
		int pos1 = 0, pos2 = 0, flag = 0, tmp = 0;
		for (int i = 1; i <= 26; i++) {
			if (du[i] & 1 && du[i] > 0)pos1 == 0 ? pos1 = i : flag = 1;
			if (du[i] & 1 && du[i] < 0)pos2 == 0 ? pos2 = i : flag = 1;
			if (has[i])(!tmp) ? tmp = find(i) : ((find(i) != tmp) ? flag = 1 : 0);
		}
		printf("Case %d: ", ++kase);
		if (flag) { printf("Poor boy!\n"); continue; }
		if (pos1) {
			g[pos2][pos1]++;//加一条未定向边使之能成为回路
			du[pos1]--; du[pos2]++;
		}
		for (int i = 1; i <= 26; i++)
			for (int j = 1; j <= 26; j++)
				if (g[i][j]) {
					addedge(i, j, g[i][j]);
					addedge(j, i, 0);
				}
		int sum = 0;
		for (int i = 1; i <= 26; i++) {
			if (du[i] > 0) {
				sum += du[i] / 2;
				addedge(s, i, du[i] / 2);
				addedge(i, s, 0);
			}
			if (du[i] < 0) {
				addedge(i, t, (-du[i]) / 2);
				addedge(t, i, 0);
			}
		}
		if (sum == dinic()) printf("Well done!\n");
		else printf("Poor boy!\n");
	}
	return 0;
}

你可能感兴趣的:(图论)