poj3020

无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数/2

  1 #include <iostream>
  2 #include <string>
  3 #include <vector>
  4 #include <cstdlib>
  5 #include <cmath>
  6 #include <map>
  7 #include <algorithm>
  8 #include <list>
  9 #include <ctime>
 10 #include <set>
 11 #include <queue>
 12 #include <cstring>
 13 #include <cstdio>
 14 using namespace std;
 15 #define INT_MAX 10000000
 16 #define N 1005
 17 #define CLR(arr, what) memset(arr, what, sizeof(arr))
 18 int capacity[N][N]; //容量
 19 int flow[N]; //残余流量
 20 int pre[N]; //前趋
 21 int n; //节点个数
 22 
 23 queue<int> Q;
 24 
 25 int BFS(int src, int des) {
 26     //初始化
 27     while (!Q.empty()) {
 28         Q.pop();
 29     }
 30     for (int i = 1; i < n + 1; i++) {
 31         pre[i] = -1;
 32     }
 33     pre[src] = 0;
 34     flow[src] = INT_MAX; //初始化源点的流量为无穷大
 35     Q.push(src);
 36     while (!Q.empty()) {
 37         int index = Q.front();
 38         Q.pop();
 39         if (index == des) { //找到了增广路径
 40             break;
 41         }
 42         for (int i = 1; i < n + 1; i++) {
 43             if (i != src && capacity[index][i] > 0 && pre[i] == -1) {
 44                 pre[i] = index;
 45                 //增广路残容流量
 46                 flow[i] = min(capacity[index][i], flow[index]);
 47                 Q.push(i);
 48             }
 49         }
 50     } //while
 51     if (pre[des] == -1) {
 52         return -1; //残留图中不存在增广路径
 53     } else {
 54         return flow[des];
 55     }
 56 }
 57 
 58 int MaxFlow(int src, int des) {
 59     int aug = 0;
 60     int sumflow = 0;
 61     while ((aug = BFS(src, des)) != -1) {
 62         int k = des; //利用前驱寻找路径
 63         while (k != src) {
 64             int last = pre[k];
 65             capacity[last][k] -= aug;
 66             capacity[k][last] += aug;
 67             k = last;
 68         }
 69         sumflow += aug;
 70     }
 71     return sumflow;
 72 }
 73 struct node {
 74     string in, out;
 75     int cap;
 76 };
 77 int checkin(string & a, string& b) {
 78     int sz = a.size();
 79     bool judge = 1;
 80     for (int i = 0; i < sz; i++) {
 81         if (a[i] == '2' || b[i] == '2') {
 82             continue;
 83         } else if (a[i] != b[i]) {
 84             judge = 0;
 85             break;
 86         }
 87     }
 88     if (1 == judge)
 89         return 1;
 90     return 0;
 91 }
 92 
 93 int cur[N]; //后继
 94 int dis[N]; //距离
 95 int gap[N]; //层结点数(用于间隙优化)
 96 int SAP(int s, int t) //源点、汇点、结点数
 97         {
 98     CLR(gap, 0);
 99     CLR(cur, 0);
100     CLR(dis, 0);
101     int u = pre[s] = s, maxflow = 0, aug = INT_MAX;
102     int v;
103     gap[0] = n;
104     while (dis[s] < n) {
105         bool flag = false;
106         for (v = cur[u]; v <= n; ++v) //寻找允许弧
107                 {
108             if (capacity[u][v] > 0 && dis[u] == dis[v] + 1) {
109                 flag = true;
110                 break;
111             }
112         }
113         if (flag) //找到允许弧
114         {
115             pre[v] = u;
116             cur[u] = v;
117             aug = min(aug, capacity[u][v]);
118             u = v;
119             if (v == t) //找到完整增广路
120                     {
121                 maxflow += aug;
122                 for (v = t; v != s; v = pre[v]) //更新残留网络
123                         {
124                     capacity[pre[v]][v] -= aug; //正向边
125                     capacity[v][pre[v]] += aug; //反向边
126                 }
127                 aug = INT_MAX;
128                 u = s; //重新从源点寻找
129             }
130         } else //找不到允许弧
131         {
132             int mindis = n;
133             for (v = 1; v <= n; ++v) //重新标号
134                     {
135                 if (capacity[u][v] && mindis > dis[v]) {
136                     cur[u] = v;
137                     mindis = dis[v];
138                 }
139             }
140             if (--gap[dis[u]] == 0) //更新断层 + 判断是否断层(间隙优化)
141                 break;
142             gap[dis[u] = mindis + 1]++; //更新断层
143             u = pre[u]; //当前弧优化
144         }
145     }
146     return maxflow;
147 }
148 
149 inline void addedge(int x, int y, int c) { // add an arc(x -> y, c); vertex: 0 ~ n-1;
150     capacity[x][y] = c;
151 }
152 int tag[N][N]; //容量
153 int dx[] = { 1, 0, -1, 0 };
154 int dy[] = { 0, 1, 0, -1 };
155 int main() {
156     int u, v, r, c, itnu;
157     cin >> itnu;
158     for (int abc = 0; abc < itnu; abc++) {
159         CLR(capacity, 0);
160         CLR(tag, 0);
161         string tmp;
162         vector<string> data;
163         cin >> r >> c;
164         for (int i = 0; i < r; i++) {
165             cin >> tmp;
166             data.push_back(tmp);
167         }
168         int node_num = 0;
169         for (int i = 0; i < r; i++) {
170             for (int j = 0; j < c; j++) {
171                 if (data[i][j] == '*') {
172                     node_num++;
173                     tag[i][j] = node_num;
174                 }
175             }
176         }
177         n = node_num * 2 + 2;
178         for (int i = 0; i < node_num; i++) {
179             addedge(0, i + 1, 1);
180             addedge(node_num + i + 1, n - 1, 1);
181         }
182         for (int i = 0; i < r; i++) {
183             for (int j = 0; j < c; j++) {
184                 if (tag[i][j] != 0) {
185                     u = tag[i][j];
186                     for (int a = 0; a < 4; a++) {
187                         int x = i + dx[a];
188                         int y = j + dy[a];
189                         if (x >= 0 && x < r && y >= 0 && y < c) {
190                             if (tag[x][y] > 0) {
191                                 v = tag[x][y] + node_num;
192                                 addedge(u, v, 1);
193                             }
194                         }
195                     }
196                 }
197             }
198         }
199 //        int sum = MaxFlow(0, n - 1);
200         int sum = SAP( 0, n - 1);
201         cout << node_num - sum / 2 << endl;
202     }
203     return 0;
204 }

from kakamilan

原文地址:https://www.cnblogs.com/kakamilan/p/3072588.html