题意:
将每个单词看为一个边,那么很明显就是一个混合图欧拉路径
分析:
首先,还是在网络流计算混合图欧拉回路的基础上进行,因为欧拉回路一定满足欧拉路径。
其次,如果有且仅有两个点入度出度差为奇数,那么给这两点加上边,判断是否存在欧拉回路。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 210;
//最大流ISAP部分
const int MAXM = 20100;
const int INF = 0x3f3f3f3f;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
void init(){
tol = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0){
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].next = head[u];
edge[tol].flow = 0;
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = rw;
edge[tol].next = head[v];
edge[tol].flow = 0;
head[v] = tol++;
}
int sap(int start,int end,int N){
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u = start;
pre[u] = -1;
gap[0] = N;
int ans = 0;
while(dep[start] < N){
if(u == end){
int Min = INF;
for(int i = pre[u]; i != -1;i = pre[edge[i^1].to])
if(Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
for(int i = pre[u];i != -1;i = pre[edge[i^1].to]){
edge[i].flow += Min;
edge[i^1].flow -= Min;
}
u = start;
ans += Min;
continue;
}
bool flag = false;
int v;
for(int i = cur[u];i != -1;i = edge[i].next){
v = edge[i].to;
if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]){
flag = true;
cur[u] = pre[v] = i;
break;
}
}
if(flag){
u = v;
continue;
}
int Min = N;
for(int i = head[u];i != -1;i = edge[i].next)
if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min){
Min = dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u] = Min+1;
gap[dep[u]]++;
if(u != start)u = edge[pre[u]^1].to;
}
return ans;
}
//the end of 最大流部分
int in[MAXN],out[MAXN];//每个点的出度和入度
char s[100];
int fa[MAXN];
int find(int x){
return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
}
bool vis[MAXN];
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
int m;
scanf("%d",&T);
for(int cs=1;cs<=T;cs++){
scanf("%d",&m);
init();
int u,v,w;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=0;i<MAXN;i++){
fa[i]=i;
}
memset(vis,0,sizeof vis);
while(m--){
scanf("%s%d",s,&w);
u=s[0]-'a'+1;
v=s[strlen(s)-1]-'a'+1;
out[u]++; in[v]++;
int fu=find(u);
int fv=find(v);
vis[u]=vis[v]=1;
if(fu!=fv) {
fa[fu]=fv;
}
if(w == 1)//双向
addedge(u,v,1);
}
bool flag = true;
int cnt=0;
vector<int>vec;
for(int i=1;i<=26;i++){
if(vis[i]&&fa[i]==i) cnt++;
if((out[i] - in[i])&1)
vec.push_back(i);
}
printf("Case %d: ",cs);
if(cnt!=1||(vec.size()!=2&&vec.size()!=0)){
printf("Poor boy!\n");
continue;
}
if(vec.size()==2){
out[vec[0]]++;in[vec[1]]++;
addedge(vec[0],vec[1],1);
}
for(int i = 1;i <= 26;i++){
if((out[i]-in[i])&1==0&&out[i] - in[i] > 0)
addedge(0,i,(out[i] - in[i])/2);
else if((out[i]-in[i])&1==0&&in[i] - out[i] > 0)
addedge(i,27,(in[i] - out[i])/2);
}
sap(0,27,28);
for(int i = head[0]; i != -1;i = edge[i].next)
if(edge[i].cap > 0 && edge[i].cap > edge[i].flow){
flag = false;
break;
}
if(flag)printf("Well done!\n");
else printf("Poor boy!\n");
}
return 0;
}