[BZOJ 1458] 士兵占领

1458: 士兵占领

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1210  Solved: 667
[Submit][Status][Discuss]

Description

有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。

Input

第一行两个数M, N, K分别表示棋盘的行数,列数以及障碍的个数。 第二行有M个数表示Li。 第三行有N个数表示Ci。 接下来有K行,每行两个数X, Y表示(X, Y)这个格子是障碍。

Output

输出一个数表示最少需要使用的士兵个数。如果无论放置多少个士兵都没有办法占领整个棋盘,输出”JIONG!” (不含引号)

Sample Input

4 4 4
1 1 1 1
0 1 0 3
1 4
2 2
3 3
4 3

Sample Output

4
数据范围
M, N <= 100, 0 <= K <= M * N

对于这道题,如果每个士兵仅对某一行或者某一列而不是两者同时作出贡献,则答案$ans$为:

\[ ans=\sum_{i=1}^m l_i +\sum_{i=1}^n c_i \]

但是我们知道一些士兵可以同时对某行和某列的和作出贡献,所以我们可以求这样的士兵的最大值,最后用上面求出的假的\(ans\)减去就可以了

而求最大值可以考虑网络流,将可以放置士兵的位置的行结点与列结点之间连一条容量为$1$的边,行/列结点分别向源点$s$ / 汇点$t$ 连一条容量为对应需求 $l_i$ 或 $c_i$的边再跑一遍最大流就可以得出结果.

至于无解情况网络流则无法处理,要在计算最大流之前进行枚举特判.

参考代码

GitHub

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <iostream>
  6 #include <algorithm>
  7 
  8 const int MAXV=210;
  9 const int MAXE=40100;
 10 const int INF=0x7FFFFFFF;
 11 
 12 struct Edge{
 13     int from;
 14     int to;
 15     int flow;
 16     Edge* rev;
 17     Edge* next;
 18 };
 19 
 20 Edge E[MAXE];
 21 Edge* head[MAXV];
 22 Edge* top=E;
 23 
 24 int m;
 25 int n;
 26 int k;
 27 int sum;
 28 int c[MAXV];
 29 int l[MAXV];
 30 int depth[MAXV];
 31 bool flag[MAXV][MAXV];
 32 
 33 int Dinic(int,int);
 34 int DFS(int,int,int);
 35 int Convert(int,int);
 36 bool BFS(int,int);
 37 bool Check();
 38 void Build();
 39 void Initialize();
 40 void Insert(int,int,int);
 41 
 42 int main(){
 43     Initialize();
 44     if(!Check()){
 45         puts("JIONG!");
 46     }
 47     else{
 48         Build();
 49         printf("%d\n",sum-Dinic(0,m+n+1));
 50     }
 51     return 0;
 52 }
 53 
 54 int Dinic(int s,int t){
 55     int ans=0;
 56     while(BFS(s,t)){
 57         ans+=DFS(s,INF,t);
 58     }
 59     return ans;
 60 }
 61 
 62 int DFS(int s,int flow,int t){
 63     if(s==t||flow==0)
 64         return flow;
 65     int tmp=flow;
 66     int k;
 67     for(Edge* i=head[s];i!=NULL;i=i->next){
 68         if(i->flow!=0&&tmp!=0&&depth[i->to]==depth[s]+1){
 69             k=DFS(i->to,std::min(tmp,i->flow),t);
 70             if(k==0){
 71                 depth[i->to]=0;
 72                 continue;
 73             }
 74             tmp-=k;
 75             i->flow-=k;
 76             i->rev->flow+=k;
 77             if(tmp==0)
 78                 break;
 79         }
 80     }
 81     return flow-tmp;
 82 }
 83 
 84 bool BFS(int s,int t){
 85     memset(depth,0,sizeof(depth));
 86     std::queue<int> q;
 87     q.push(s);
 88     depth[s]=1;
 89     while(!q.empty()){
 90         s=q.front();
 91         q.pop();
 92         for(Edge* i=head[s];i!=NULL;i=i->next){
 93             if(depth[i->to]==0&&i->flow!=0){
 94                 depth[i->to]=depth[s]+1;
 95                 q.push(i->to);
 96                 if(i->to==t)
 97                     return true;
 98             }
 99         }
100     }
101     return false;
102 }
103 
104 void Build(){
105     for(int i=1;i<=m;i++){
106         for(int j=1;j<=n;j++){
107             if(!flag[i][j])
108                 Insert(i,j+m,1);
109         }
110     }
111 }
112 
113 void Initialize(){
114     scanf("%d%d%d",&m,&n,&k);
115     for(int i=1;i<=m;i++){
116         scanf("%d",l+i);
117         Insert(0,i,l[i]);
118         sum+=l[i];
119     }
120     for(int i=1;i<=n;i++){
121         scanf("%d",c+i);
122         Insert(i+m,n+m+1,c[i]);
123         sum+=c[i];
124     }
125     int a,b;
126     for(int i=0;i<k;i++){
127         scanf("%d%d",&a,&b);
128         flag[a][b]=true;
129     }
130 }
131 
132 bool Check(){
133     int cnt;
134     for(int i=1;i<=m;i++){
135         for(int j=1;j<=n;j++){
136             if(!flag[i][j])
137                 cnt++;
138         }
139         if(cnt<l[i])
140             return false;
141     }
142     for(int j=1;j<=n;j++){
143         for(int i=1;i<=m;i++){
144             if(!flag[i][j])
145                 cnt++;
146         }
147         if(cnt<c[j])
148             return false;
149     }
150     return true;
151 }
152 
153 inline void Insert(int a,int b,int flow){
154     top->from=a;
155     top->to=b;
156     top->flow=flow;
157     top->next=head[a];
158     head[a]=top;
159     top->rev=top+1;
160     top++;
161     top->from=b;
162     top->to=a;
163     top->flow=0;
164     top->next=head[b];
165     head[b]=top;
166     top->rev=top-1;
167     top++;
168 }
Backup

 

posted @ 2017-07-31 16:49  rvalue  阅读(272)  评论(0编辑  收藏  举报