很容易看出是混合图的欧拉路径问题,注意不是欧拉回路,这是有很大区别的。
上一篇博文介绍用最大流解决混合图的欧拉回路问题,这里的混合图的欧拉路径问题,采用化归的思想,转化为欧拉回路求解。如果没有入度+出度是奇数的点,那么不需要化归;如果这样的点有两个,那么将这两个点随意连一条边,容量为1,转化为欧拉回路问题;如果这样的点不是0或2个,证明没有欧拉路径,至此就解决了本题。
AC代码:
#include <math.h>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 5010;
const int INF = 0x3f3f3f3f;
int S,T,s1,s2,totflow;
int I[30],O[30];
int dis[30],Q[30],h,t;
int cnt,head[30],father[30],vis[30];
struct edge{
int v,c,next;
}node[MAX];
void Init(){
cnt = 0;
totflow = 0;
for(int i=1; i<=26; i++) father[i] = i;
memset(I, 0, sizeof(I));
memset(O, 0, sizeof(O));
memset(vis, 0, sizeof(vis));
memset(head, -1, sizeof(head));
}
int Find(int x){
if(x != father[x])
father[x] = Find(father[x]);
return father[x];
}
void addedge(int u, int v, int c){
node[cnt].v = v;
node[cnt].c = c;
node[cnt].next = head[u];
head[u] = cnt++;
}
bool is_connect(){//并查集判断图是否连通
int tmp = 0;
for(int i=1; i<=26; i++){
if(!vis[i]) continue;
if(father[i] == i) tmp++;
}
if(tmp > 1) return false;
return true;
}
bool buildflow(){
s1 = -1, s2 = -1;
int tmp = 0;
for(int i=1; i<=26; i++){
if(!vis[i]) continue;
if((O[i] + I[i])&1){
tmp++;
if(s1 != -1) s2 = i;
else s1 = i;
}
if(O[i] > I[i]){
int c = (O[i]-I[i]) >> 1;
addedge(S, i, c);
addedge(i, S, 0);
totflow += c;
}
else{
int c = (I[i] - O[i]) >> 1;
addedge(i, T, c);
addedge(T, i, 0);
}
}
if(tmp != 0 && tmp != 2) return false;
if(tmp == 2){//化归的操作
O[s1]++;
I[s2]++;
addedge(s1, s2, 1);
addedge(s2, s1, 0);
}
return true;
}
bool 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;
if(node[i].c > 0 && dis[v] == -1){
dis[v] = dis[u] + 1;
Q[++t] = v;
if(v == T) return true;
}
}
}
return false;
}
int DFS(int id, int minflow){//增广过程
if(id == T) return minflow;
int a = 0;
for(int i=head[id]; i!=-1; i=node[i].next){
int v = node[i].v;
if(node[i].c > 0 && dis[v] == dis[id] + 1
&& (a = DFS(v, min(node[i].c, minflow)))){
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 cas,t=0;
scanf("%d",&cas);
while(cas--){
int n,d;
scanf("%d",&n);
char str[25];
Init();
for(int i=0; i<n; i++){
scanf("%s",str);
scanf("%d",&d);
int l = strlen(str);
int u = str[0]-'a'+1, v = str[l-1]-'a'+1;
father[Find(u)] = Find(v);
vis[v] = vis[u] = 1;
O[u]++, I[v]++;
if(d){
addedge(u, v, 1);
addedge(v, u, 0);
}
}
printf("Case %d: ",++t);
if(!is_connect()) {
puts("Poor boy!");
continue;
}
S = 0, T = 27;//设置源点 汇点
int flag = buildflow(), ans = Dinic();
if(!flag) {
puts("Poor boy!");
continue;
}
if(ans == totflow) puts("Well done!");//满流
else puts("Poor boy!");
}
return 0;
}