题意:有个人有一种记单词方法,如果一个单词的最后一个字母和另外一个单词的首字母相同,他就同时可以记住,现在他想按照这样的规则把n个单词串起来(就是一个单词的最后一个字母和另外一个单词的首字母相同),有些单词的回文串也是有意义的,因此他既可以正着记,也可以倒着记,现在问他能不能调整那些回文串有意义的单词的正序逆序把这n个单词串起来。
混合图的欧拉路径,不是欧拉回路。如果是混合图的欧拉回路问题,在《网络流建模汇总》这篇论文里已经有了具体的方案了。这里需要做的处理就是,如果存在合法路径,而这个路径不构成回路的话,那么我们可以人为的找出起点和终点(就是度数为奇数的点,且只有两个,根据入度出度谁大谁小可以确定谁是起点谁是终点),然后从终点到起点去连一条容量为1的边,如此一来便构造出了一个的回路。再去按混合图欧拉回路的建图方法去判断是否存在欧拉回路就可以了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define INF 1<<30 6 #define maxn 30 7 #define maxm 10000 8 using namespace std; 9 10 int v[maxm],next[maxm],w[maxm]; 11 int first[maxn],d[maxn],work[maxn],q[maxn]; 12 int e,S,T; 13 int in[30],out[30],fa[30],used[30]; 14 15 void init(){ 16 e = 0; 17 memset(first,-1,sizeof(first)); 18 } 19 20 void add_edge(int a,int b,int c){ 21 //printf("add:%d to %d,cap = %d ",a,b,c); 22 v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++; 23 v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++; 24 } 25 26 int bfs(){ 27 int rear = 0; 28 memset(d,-1,sizeof(d)); 29 d[S] = 0;q[rear++] = S; 30 for(int i = 0;i < rear;i++){ 31 for(int j = first[q[i]];j != -1;j = next[j]) 32 if(w[j] && d[v[j]] == -1){ 33 d[v[j]] = d[q[i]] + 1; 34 q[rear++] = v[j]; 35 if(v[j] == T) return 1; 36 } 37 } 38 return 0; 39 } 40 41 int dfs(int cur,int a){ 42 if(cur == T) return a; 43 for(int &i = work[cur];i != -1;i = next[i]){ 44 if(w[i] && d[v[i]] == d[cur] + 1) 45 if(int t = dfs(v[i],min(a,w[i]))){ 46 w[i] -= t;w[i^1] += t; 47 return t; 48 } 49 } 50 return 0; 51 } 52 53 int dinic(){ 54 int ans = 0; 55 while(bfs()){ 56 memcpy(work,first,sizeof(first)); 57 while(int t = dfs(S,INF)) ans += t; 58 } 59 return ans; 60 } 61 62 int find(int x){ 63 return x == fa[x] ? x : fa[x] = find(fa[x]); 64 } 65 66 int main() 67 { 68 int nkase,n; 69 scanf("%d",&nkase); 70 for(int kase = 1;kase <= nkase;kase++){ 71 S = 26,T = 27; 72 memset(in,0,sizeof(in)); 73 memset(out,0,sizeof(out)); 74 memset(used,0,sizeof(used)); 75 for(int i = 0;i < 26;i++) 76 fa[i] = i; 77 init(); 78 scanf("%d",&n); 79 char str[30]; 80 int tmp; 81 for(int i = 0;i < n;i++){ 82 scanf("%s%d",str,&tmp); 83 int a = str[0]-'a',b = str[strlen(str)-1]-'a'; 84 out[a]++,in[b]++; 85 used[a] = 1,used[b] = 1; 86 if(tmp == 1) add_edge(a,b,1); 87 int x = find(a),y = find(b); 88 if(x != y) fa[x] = y; 89 } 90 bool flag = 1; 91 for(int i = 0;i < 26;i++) if(used[i] && flag) 92 for(int j = 0;j < 26;j++) if(used[j] && flag) 93 if(find(i) != find(j)){ 94 flag = false; 95 break; 96 } 97 int start = -1,end = -1,cnt = 0,sum = 0; 98 for(int i = 0;i < 26;i++){ 99 //printf("in[%d] = %d,out[%d] = %d ",i,in[i],i,out[i]); 100 int x = out[i]-in[i]; 101 if(x > 0){ 102 add_edge(S,i,x/2); 103 sum += x/2; 104 if(x % 2 == 1){ 105 cnt++; 106 start = i; 107 } 108 } 109 if(x < 0){ 110 add_edge(i,T,-x/2); 111 if(x % 2 == -1){ 112 cnt++; 113 end = i; 114 } 115 } 116 } 117 //printf("start = %d,end = %d,sum = %d ",start,end,sum); 118 if(cnt == 2 || cnt == 0){ 119 if(start != -1 && end != -1) 120 add_edge(end,start,1); 121 } 122 else flag = false; 123 if(flag && dinic() == sum) printf("Case %d: Well done! ",kase); 124 else printf("Case %d: Poor boy! ",kase); 125 } 126 return 0; 127 }