ICPC Pacific Northwest Regional Contest 2016 Maximum Islands(二分图最大独立集)

末鹿安然 提交于 2020-08-09 17:16:13

Maximum Islands

思路:预处理‘L’周围包围‘W’。‘L’独自成为岛屿为最优,我们‘L’,‘W’交替处理的图((x+y)%2为同一个集合),分为两个集合,相邻的‘L’和‘W’有边,同一个集合没边,变成二分图的最大独立集问题,得出最多的互不相邻的点就是最大岛屿数量。因为我们匹配的出发点是全图,所以匹配数 = match / 2。

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <queue>
  6 
  7 using namespace std;
  8 
  9 const int N = 50;
 10 int mv_x[] = {1, -1, 0, 0};
 11 int mv_y[] = {0, 0, 1, -1};
 12 char mp[N][N]; //地图
 13 vector<int > E[N * N]; //
 14 int pre[N * N]; 
 15 bool vis[N * N];
 16 bool viss[N][N]; //是否访问过
 17 bool e[N * N][N * N]; //重复边判定
 18 int id[N][N]; //编号
 19 int n, m, island, poi;
 20 
 21 inline bool check(int x, int y)
 22 {
 23     return x >= 0 && x < n && y >= 0 && y < m;
 24 }
 25 
 26 void dfs_island(int x, int y)
 27 {
 28     mp[x][y] = 'W';
 29     for(int p = 0; p < 4; ++p){
 30         int dx = x + mv_x[p];
 31         int dy = y + mv_y[p];
 32 
 33         if(check(dx, dy) && mp[dx][dy] == 'L'){
 34             dfs_island(dx, dy);
 35         }
 36     }
 37 }
 38 
 39 inline void add(int u, int v)
 40 {
 41     E[u].push_back(v);
 42     E[v].push_back(u);
 43 }
 44 
 45 void dfs_cloud(int x, int y)
 46 {
 47     viss[x][y] = 1;
 48     for(int p = 0; p < 4; ++p){
 49         int dx = x + mv_x[p];
 50         int dy = y + mv_y[p];
 51 
 52         if(check(dx, dy) && mp[dx][dy] == 'C'){
 53             int id1 = min(id[x][y], id[dx][dy]);
 54             int id2 = max(id[x][y], id[dx][dy]);
 55             if(e[id1][id2] == 0){
 56                 e[id1][id2] = 1;
 57                 add(id1, id2);
 58             }
 59             if(!viss[dx][dy]){
 60                 viss[dx][dy] = 1;
 61                 dfs_cloud(dx, dy);
 62             }      
 63         }
 64     }
 65 }
 66 
 67 bool find(int u)
 68 {
 69     for(auto v : E[u]){
 70         if(vis[v]) continue;
 71         vis[v] = 1;
 72         if(!pre[v] || find(pre[v])){
 73             pre[v] = u;
 74             return true;
 75         }
 76     }
 77     return false;
 78 }
 79 
 80 void show()
 81 {
 82     for(int i = 0; i < n; ++i){
 83         for(int j = 0; j < m; ++j){
 84             cout << mp[i][j];
 85         }cout << endl;
 86     }
 87 }
 88 
 89 void solve()
 90 {
 91 
 92     scanf("%d%d", &n, &m);
 93     for(int i = 0; i < n; ++i) scanf("%s", &mp[i]);
 94     //预处理L
 95     for(int i = 0; i < n; ++i){
 96         for(int j = 0; j < m; ++j){
 97             if(mp[i][j] == 'L'){
 98                 for(int p = 0; p < 4; ++p){
 99                     int dx = i + mv_x[p];
100                     int dy = j + mv_y[p];
101                     if(check(dx, dy) && mp[dx][dy] == 'C'){
102                         mp[dx][dy] = 'W';
103                     }
104                 }
105             }
106         }
107     }
108 
109     //统计岛屿个数,编号
110     for(int i = 0; i < n; ++i){
111         for(int j = 0; j < m; ++j){
112             if(mp[i][j] == 'L'){
113                 island++;
114                 dfs_island(i, j);
115             }else if(mp[i][j] == 'C') id[i][j] = ++poi;
116         }
117     }
118 
119     //建图
120     for(int i = 0; i < n; ++i){
121         for(int j = 0; j < m; ++j){
122             if(mp[i][j] == 'C'){
123                 dfs_cloud(i, j);
124             }
125         }
126     }
127 
128     //匹配
129     int match = 0;
130     for(int i = 0; i < n; ++i){
131         for(int j = 0; j < m; ++j){
132             if(!id[i][j]) continue;
133             for(int x = 1; x <= poi; ++x) vis[x] = 0; 
134             if(find(id[i][j])) match++;
135         }
136     }
137 
138     //printf("island = %d\n", island + poi - match / 2);
139     printf("%d\n", island + poi - match / 2);
140 }
141 
142 
143 int main()
144 {
145 
146     solve();
147 
148     return 0;
149 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!