P4311 士兵占领 (网络流)

题目链接

 

 

解法:

首先考虑逆向思维,求最少要使用的士兵个数,转化为,初始的时候所有能放士兵的地方都放了士兵的情况下,最多能删掉多少个士兵。

1. 给每一行每一列分别建一个点,对于所有非障碍坐标(x,y),从x行对应的点 向 y列对应的点连一条容量为1的边,表示这个位置的士兵最多可以删除一次。

2. 源点向每一行对应的点连边,容量为这一行能删除的士兵个数的最大值(即 列数m - 这一行的障碍数 - 这一行需要的士兵数L[i])。

3. 每一列对应的点向汇点连边,容量为这一列能删除的士兵个数的最大值(即 行数n - 这一列的障碍数 - 这一列需要的士兵数C[i])。

这样跑一个最大流,每一个单位的流量表示删除一个士兵,不难证明 任意一种流量状态都与一种合法的士兵删除方案相对应。

特判无解的情况,如果所有能放士兵的地方都放上了士兵,仍然存在行或列不满足限制条件,输出无解即可。

copy from: https://www.luogu.com.cn/blog/user36456/solution-p4311 

 

Code:

  1 #include <bits/stdc++.h>
  2 #define LL long long
  3 #define INF 0x3f3f3f3f;
  4 using namespace std;
  5 
  6 int M, N, K;
  7 int row[110], col[110];
  8 int grid[110][110];
  9 int S, T;
 10 int maxsub;
 11 struct Edge{
 12     int next, from, to, remain;
 13 }e[25000];
 14 int en;
 15 int head[300];
 16 queue<int> q;
 17 int visited[300];
 18 int preEdge[300];
 19 int minflow[300];
 20 
 21 void addEdge(int from, int to, int flow){
 22     e[en].next=head[from];
 23     e[en].from=from;
 24     e[en].to=to;
 25     e[en].remain=flow;
 26     head[from]=en;
 27     ++en;
 28 }
 29 
 30 void add(int from, int to, int flow){
 31     addEdge(from, to, flow);
 32     addEdge(to, from, 0);
 33 }
 34 
 35 void bfs(){
 36     memset(visited,0,sizeof(visited));
 37     memset(preEdge,-1,sizeof(preEdge));
 38     memset(minflow,0,sizeof(minflow));
 39     q.push(S);
 40     visited[S]=1;
 41     minflow[S]=INF;
 42     while(!q.empty()){
 43         int u=q.front();
 44         q.pop();
 45         for(int i=head[u];i!=-1;i=e[i].next){
 46             if(e[i].remain>0 && !visited[e[i].to]){
 47                 visited[e[i].to]=1;
 48                 minflow[e[i].to]=min(minflow[u],e[i].remain);
 49                 preEdge[e[i].to]=i;
 50                 q.push(e[i].to);
 51             }
 52         }
 53     }
 54 }
 55 
 56 void EK(){
 57     while(true){
 58         bfs();
 59         if(preEdge[T]==-1) break;
 60         maxsub+=minflow[T];
 61         int v=T;
 62         while(true){
 63             int edge=preEdge[v];
 64             if(edge==-1) break;
 65             e[edge].remain-=minflow[T];
 66             e[edge^1].remain+=minflow[T];
 67             v=e[edge].from;
 68         }
 69     }
 70 }
 71 
 72 int main(){
 73     memset(head,-1,sizeof(head));
 74     scanf("%d %d %d", &M, &N, &K);
 75     for(int i=1;i<=M;++i){
 76         scanf("%d", row+i);
 77     }
 78     for(int i=1;i<=N;++i){
 79         scanf("%d", col+i);
 80     }
 81     for(int i=1;i<=K;++i){
 82         int x,y;
 83         scanf("%d %d", &x, &y);
 84         grid[x][y]=1;
 85     }
 86     S=0;
 87     T=M+N+1;
 88     for(int i=1;i<=M;++i){
 89         int blocks=0;
 90         for(int j=1;j<=N;++j){
 91             if(grid[i][j]){
 92                 blocks++;
 93             }else{
 94                 add(i,j,1);
 95             }
 96         }
 97         if(N-blocks-row[i]<0) {
 98             printf("JIONG!");
 99             return 0;
100         }
101         add(S,i,N-blocks-row[i]);
102     }
103 
104     for(int j=1;j<=N;++j){
105         int blocks=0;
106         for(int i=1;i<=M;++i){
107             if(grid[i][j]) blocks++;
108         }
109         if(M-blocks-col[j]<0){
110             printf("JIONG!");
111             return 0;
112         }
113         add(j,T,M-blocks-col[j]);
114     }
115 
116     EK();
117     int res=M*N-K-maxsub;
118     printf("%d", res);
119     return 0;
120 }

 

posted @ 2020-01-31 16:17  feibilun  阅读(142)  评论(0编辑  收藏  举报