题意:
给一堆单词..有的单词是可以反过来的..两个单词能连接exactly前面单词的最后一个字母等于后面一个单词的第一个字母..问能否将所有单词连成一串....
题解:
同样以字母为点,单词为边..把判断哈密顿通路转化成判断欧拉通路...
判断混合图是否存在欧拉通路: 无向边任意定向后,看有多少个点入度多了且度为奇数..有多少个点出度多了且度为奇数..若两个数量都为0..或者都为1并且加一条有向边连接两点(入度多了的指向出度多了的)..然后就和混合图欧拉回路一样的判断了...用最大流解决..话说此类问题一定不要忘记判断连通性!!!
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<time.h>
#include<map>
#include<algorithm>
#define ll long long
#define eps 1e-5
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 50
#define MAXM 500005
using namespace std;
int father[50];
bool used[50];
int getfather(int x)
{
if (father[x]==x) return x;
return father[x]=getfather(father[x]);
}
struct Dinic
{
struct node
{
int x,y,c,next;
}line[MAXM];
int Lnum,_next[MAXN],dis[MAXN];
void initial(int n)
{
for (int i=0;i<=n;i++) _next[i]=-1;
Lnum=-1;
}
void addline(int x,int y,int c)
{
line[++Lnum].next=_next[x],_next[x]=Lnum;
line[Lnum].x=x,line[Lnum].y=y,line[Lnum].c=c;
line[++Lnum].next=_next[y],_next[y]=Lnum;
line[Lnum].x=y,line[Lnum].y=x,line[Lnum].c=0;
}
bool BFS(int s,int e)
{
queue<int> Q;
while (!Q.empty()) Q.pop();
memset(dis,0,sizeof(dis));
dis[s]=1;
Q.push(s);
while (!Q.empty())
{
int h,k;
h=Q.front(),Q.pop();
if (h==e) return dis[e];
for (k=_next[h];k!=-1;k=line[k].next)
if (line[k].c && !dis[line[k].y])
dis[line[k].y]=dis[h]+1,Q.push(line[k].y);
}
return false;
}
int dfs(int x,int flow,int e)
{
if (x==e) return flow;
int temp,cost=0;
for (int k=_next[x];k!=-1;k=line[k].next)
if (line[k].c && dis[line[k].y]==dis[x]+1)
{
temp=dfs(line[k].y,min(flow-cost,line[k].c),e);
if (temp)
{
line[k].c-=temp,line[k^1].c+=temp;
cost+=temp;
if (flow==cost) return cost;
}else dis[line[k].y]=-1;
}
return cost;
}
int MaxFlow(int s,int e)
{
int MaxFlow=0;
while (BFS(s,e)) MaxFlow+=dfs(s,oo,e);
return MaxFlow;
}
}T;
bool judge(int s,int e,int id,int *d,int n)
{
if (n==1) return true;
int i;
if (n==1) return true;
for (i=0;i<26;i++)
if (used[i] && getfather(i)!=id) return false;
int sum=0,t1=-1,t2=-1;
for (i=0;i<26;i++)
if (d[i]<0)
{
if (d[i]%2)
{
if (t1!=-1) return false;
t1=i,d[i]++;
}
d[i]/=2;
T.addline(s,i,-d[i]),sum-=d[i];
}else
if (d[i]>0)
{
if (d[i]%2)
{
if (t2!=-1) return false;
t2=i,d[i]++;
}
d[i]/=2;
T.addline(i,e,d[i]),sum+=d[i];
}
sum/=2;
if (t1>=0 && t2==-1 || t1==-1 && t2>=0) return false;
if (T.MaxFlow(s,e)==sum) return true;
else return false;
}
int main()
{
int s,e,C,m,cases,i,n,d[50],x,y,tp;
char ss[22];
scanf("%d",&C);
for (cases=1;cases<=C;cases++)
{
scanf("%d",&n);
s=30,e=31;
T.initial(e);
memset(d,0,sizeof(d));
memset(used,false,sizeof(used));
for (i=0;i<=40;i++) father[i]=i;
while (n--)
{
scanf("%s%d",ss,&tp);
x=ss[0]-'a',y=ss[strlen(ss)-1]-'a';
d[x]--,d[y]++;
father[getfather(x)]=getfather(y);
used[x]=used[y]=true;
m=getfather(x);
if (tp) T.addline(x,y,1);
}
printf("Case %d: ",cases);
if (judge(s,e,m,d,26)) printf("Well done!\n");
else printf("Poor boy!\n");
}
return 0;
}