HDU-3472(混合图判断欧拉路 + ISAP)
题目大意:给出n个单词,其中一些单词翻转后还是单词。求是否能首尾相接连成一条链。
将每个单词的首尾字母作为端点,如果这个单词可以翻转,就看作一条双向边。否则,就看作一条单向边。
用最大流处理混合图(既有双向边又有单向边)欧拉回路的时候,先忽略初始图中的有向边。为无向边指定一个方向并保留。
然后建立一个源点s,把s连向所有度数>0的边,容量是度数/2。
建立一个汇点t,把所有度数<0的边连向t,容量是度数/2。
所有没连接到s或t的边,容量都为1。
如果从s出发的所有边都满流,则存在欧拉回路。在本题中,不一定要求得欧拉回路,欧拉路也可以。
如果图中没有度数为奇数的点,那么直接判断欧拉回路。如果图中恰有两个度数为奇数的点,在这两点之间连接一条容量为1的边,再判断欧拉回路。
(记得判断图的联通性)
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<cmath> 6 #include<set> 7 8 #define cl(a, n) memset(a, n, sizeof(a)) 9 #define cpy(a, b) memcpy(a, b, sizeof(b)) 10 11 using namespace std; 12 typedef long long ll; 13 const int maxn = 1e5 + 5; 14 const int maxm = 4e5 + 5; 15 const int INF = 0x3f3f3f3f; 16 17 struct Edge{ 18 int to, Next, cap, flow, c; 19 }edge[maxm]; 20 21 int tot; 22 int head[maxn]; 23 int gap[maxn], dep[maxn], cur[maxn]; 24 25 int in[maxn], out[maxn]; 26 int vis[maxn]; 27 28 int f[maxn]; 29 30 void init(){ 31 tot = 0; 32 cl(head, -1); 33 cl(in, 0); 34 cl(out, 0); 35 cl(vis, 0); 36 cl(f, 0); 37 } 38 39 void add(int u, int v, ll w){ 40 edge[tot].to = v; edge[tot].cap = w; edge[tot].Next = head[u]; 41 edge[tot].flow = 0; head[u] = tot++; 42 edge[tot].to = u; edge[tot].cap = 0; edge[tot].Next = head[v]; 43 edge[tot].flow = 0; head[v] = tot++; 44 } 45 46 int Q[maxn]; 47 void bfs(int st, int ed){ 48 memset(dep, -1, sizeof(dep)); 49 memset(gap, 0, sizeof(gap)); 50 gap[0] = 1; 51 int front = 0, rear = 0; 52 dep[ed] = 0; 53 Q[rear++] = ed; 54 while(front != rear){ 55 int u = Q[front++]; 56 for(int i = head[u]; i != -1; i = edge[i].Next){ 57 int v = edge[i].to; 58 if(dep[v] != -1) continue; 59 Q[rear++] = v; 60 dep[v] = dep[u] + 1; 61 gap[dep[v]]++; 62 } 63 } 64 } 65 66 int S[maxn]; 67 int sap(int st, int ed, int N){ 68 bfs(st, ed); 69 memcpy(cur, head, sizeof(head)); 70 int top = 0; 71 int u = st; 72 int ans = 0; 73 while(dep[st] < N){ 74 if(u == ed){ 75 int Min = INF; 76 int inser; 77 for(int i = 0; i < top; i++) 78 if(Min > edge[S[i]].cap - edge[S[i]].flow){ 79 Min = edge[S[i]].cap - edge[S[i]].flow; 80 inser = i; 81 } 82 for(int i = 0; i < top; i++){ 83 edge[S[i]].flow += Min; 84 edge[S[i] ^ 1].flow -= Min; 85 } 86 ans += Min; 87 top = inser; 88 u = edge[S[top] ^ 1].to; 89 continue; 90 } 91 bool flag = false; 92 int v; 93 for(int i = cur[u]; i != -1; i = edge[i].Next){ 94 v = edge[i].to; 95 if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]){ 96 flag = true; 97 cur[u] = i; 98 break; 99 } 100 } 101 if(flag){ 102 S[top++] = cur[u]; 103 u = v; 104 continue; 105 } 106 int Min = N; 107 for(int i = head[u]; i != -1; i = edge[i].Next){ 108 if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min){ 109 Min = dep[edge[i].to]; 110 cur[u] = i; 111 } 112 } 113 gap[dep[u]]--; 114 if(!gap[dep[u]]) return ans; 115 dep[u] = Min + 1; 116 gap[dep[u]]++; 117 if(u != st) u = edge[S[--top] ^ 1].to; 118 } 119 return ans; 120 } 121 122 123 int get(int x){ 124 if(x != f[x]) return f[x] = get(f[x]); 125 else return f[x]; 126 } 127 128 void Union(int x, int y){ 129 x = get(x); 130 y = get(y); 131 if(x != y) f[x] = y; 132 } 133 134 int main() 135 { 136 int T; 137 scanf("%d", &T); 138 for(int K = 1; K <= T; K++){ 139 init(); 140 int n; 141 scanf("%d", &n); 142 for(int i = 0; i <= 26; i++) f[i] = i; 143 int s = 0, t = 27, num = 0; 144 for(int i = 1; i <= n; i++){ 145 char s[205]; 146 int c; 147 scanf("%s%d", s, &c); 148 int u = s[0] - 'a' + 1, v = s[strlen(s) - 1] - 'a' + 1; 149 out[u]++; in[v]++; 150 int x = get(u); 151 int y = get(v); 152 if(x != y) f[x] = y; 153 if(c == 1){ 154 add(u, v, 1); 155 } 156 } 157 int cnt = 0; 158 int odd = 0; 159 int sum = 0; 160 int u = 0; 161 for(int i = 1; i <= 26; i++){ 162 if(!out[i] && !in[i]) continue; 163 if(f[i] == i) cnt++; 164 if(cnt > 1) break; 165 if((out[i] - in[i])&1){ 166 if(odd == 2) { 167 out[u]++; in[i]++; 168 add(u, i, 1); 169 } 170 u = i; 171 odd++; 172 } 173 if(out[i]-in[i] > 0) { 174 add(s, i, (out[i] - in[i]) / 2); 175 sum += (out[i] - in[i]) / 2; 176 } 177 else if((out[i]-in[i]) < 0) add(i, t, (in[i] - out[i]) / 2); 178 } 179 printf("Case %d: ", K); 180 if(cnt != 1 || (odd != 0 && odd != 2)){ 181 printf("Poor boy!\n"); 182 } 183 else if(sap(s, t, 28) == sum){ 184 printf("Well done!\n"); 185 } 186 else{ 187 printf("Poor boy!\n"); 188 } 189 } 190 return 0; 191 }