P3355 骑士共存问题最小点覆盖网络流24题

Posted orangeko

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3355 骑士共存问题最小点覆盖网络流24题相关的知识,希望对你有一定的参考价值。

技术图片

 

 

 

思路

  显然棋盘上的每个点有三种形态:障碍物,马,已存的马能跳到的不能放马的点

  显然1、3在处理时可以归为一类,则共有两种点态。

  所以这题可以看成一个二分图来做

  每个马最多能覆盖棋盘上的八个点位

  这就形似最大独立集的概念了

  把所有独立集和障碍物都染色,剩下的就是就是可以放马的点

 

CODE

 

技术图片
  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 
  6 
  7 const int maxn = 1e6 + 7;
  8 
  9 const int inf = 0x3f3f3f3f;
 10 
 11 
 12 
 13 template<class T>inline void read(T &res)
 14 
 15 {
 16 
 17     char c;T flag=1;
 18 
 19     while((c=getchar())<0||c>9)if(c==-)flag=-1;res=c-0;
 20 
 21     while((c=getchar())>=0&&c<=9)res=res*10+c-0;res*=flag;
 22 
 23 }
 24 
 25 
 26 
 27 struct edge{int from,to,cap,flow;};
 28 
 29 int s, t, n, m;
 30 
 31 struct isap
 32 
 33 {
 34 
 35     int n,s,t,p[maxn],d[maxn],cur[maxn],num[maxn];
 36 
 37     bool vis[maxn];
 38 
 39     vector<int>g[maxn];
 40 
 41     vector<edge>edges;
 42 
 43     void init(int n,int s,int t) {
 44 
 45         this->n = n;
 46 
 47         this->s = s;
 48 
 49         this->t = t;
 50 
 51         for(int i = 1;i <= n;i++) g[i].clear();
 52 
 53         edges.clear();
 54 
 55     }
 56 
 57     void addegde(int from,int to,int cap) {
 58 
 59         edges.push_back((edge){from, to, cap, 0});
 60 
 61         edges.push_back((edge){to, from, 0, 0});
 62 
 63         int m = edges.size();
 64 
 65         g[from].push_back(m-2);
 66 
 67         g[to].push_back(m-1);
 68 
 69     }
 70 
 71 
 72 
 73     int augment() {///找增广路
 74 
 75         int x = t,a = inf;
 76 
 77         while(x!=s) {
 78 
 79             a = min(a, edges[p[x]].cap - edges[p[x]].flow);
 80 
 81             x = edges[p[x]].from;
 82 
 83         }
 84 
 85         x=t;
 86 
 87         while(x != s) {
 88 
 89             edges[p[x]].flow += a;
 90 
 91             edges[p[x]^1].flow = -a;
 92 
 93             x = edges[p[x]].from;
 94 
 95         }
 96 
 97         return a;
 98 
 99     }
100 
101     int maxflow() {///更新最大流
102 
103         int flow = 0;
104 
105         memset(num, 0, sizeof(num));
106 
107         memset(cur, 0, sizeof(cur));
108 
109         for(int i = 1; i <= n; i++) num[d[i]]++;
110 
111         int x = s;
112 
113         while(d[s] < n) {///最长的一条链上,最大的下标是nv-1,如果大于等于nv说明已断层
114 
115             if(x == t) {
116 
117                 flow += augment();
118 
119                 x = s;//回退
120 
121             }
122 
123             bool ok = 0;
124 
125             for(int i = cur[x]; i < g[x].size(); i++) {
126 
127                 edge &e = edges[g[x][i]];
128 
129                 if(d[x] == d[e.to] + 1 && e.cap > e.flow) {
130 
131                     p[e.to] = g[x][i];
132 
133                     cur[x] = i;x = e.to;
134 
135                     ok = 1;
136 
137                     break;
138 
139                 }
140 
141             }
142 
143             if(!ok) {
144 
145                 int m = n-1;
146 
147                 for(int i = 0; i < g[x].size();i++) {
148 
149                     edge &e=edges[g[x][i]];
150 
151                     if(e.cap>e.flow) m=min(m,d[e.to]);
152 
153                 }
154 
155                 num[d[x]]--;
156 
157                 if(!num[d[x]]) break;
158 
159                 d[x] = m+1;
160 
161                 num[d[x]]++;
162 
163                 cur[x] = 0;
164 
165                 if(x != s) x = edges[p[x]].from;
166 
167             }
168 
169         }
170 
171         return flow;
172 
173     }
174 
175 }ISAP;
176 
177 inline int id(int x, int y) {
178     return (x-1) * n + y;
179 }
180 
181 int a[507][507];
182 
183 int dr[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
184 int dc[8] = {1, -1, 2, -2, 2, -2, 1, -1};
185 
186 int main()
187 {
188     read(n); read(m);
189     
190     memset(a, 0, sizeof(a));
191     s = 0, t = n * n + 1;
192     ISAP.init(n * n * 2, s, t);
193     for ( int i = 1; i <= m; ++i ) {
194         int x, y;
195         read(x); read(y);
196         a[x][y] = 1;
197     }
198     for ( int i = 1; i <= n; ++i ) {
199         for ( int j = 1; j <= n; ++j ) {
200             if(a[i][j])
201                 continue;
202             if((i + j) & 1) {
203                 ISAP.addegde(s, id(i, j), 1);
204                 for ( int k = 0; k <= 7; ++k ) {
205                     int x = i + dr[k], y = j + dc[k];
206                     if(x < 1 || x > n || y < 1 || y > n) {
207                         continue;
208                     }
209                     ISAP.addegde(id(i, j), id(x, y), inf);
210                 }
211             }
212             else {
213                 ISAP.addegde(id(i, j), t, 1);
214             }
215         }
216     }
217     int maxflow = ISAP.maxflow();
218     //dbg(maxflow);
219     int ans = n * n - m - maxflow;
220     cout << ans << endl;
221     return 0;
222 }
View Code

 

以上是关于P3355 骑士共存问题最小点覆盖网络流24题的主要内容,如果未能解决你的问题,请参考以下文章

[网络流24题] 骑士共存问题

网络流24题骑士共存问题(最大流)

P3355 骑士共存问题 网络流

网络流24题骑士共存问题

洛谷 P3355 骑士共存问题最小割

P3355 骑士共存问题