题目链接: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;
}