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 }

 

posted @ 2021-03-30 19:52  章楠雨  阅读(107)  评论(0编辑  收藏  举报