[BZOJ1458] 士兵占领

1458: 士兵占领

Time Limit: 10 Sec  Memory Limit: 64 MB

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
 
 

SOLUTION

这题就是如果一个士兵所在的行和列都需要士兵,那么这个士兵就可以做出两个贡献,在刚开始的时候统计最差的士兵数量之和,也就是需要就加上,然后行和列建边,跑一边最大流,找出最多的可以做出两个贡献的士兵,然后用sum减去即可

找最小的值可以考虑最大流再相减

 

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8 # define INF 100000
  9 using namespace std;
 10 int n,m,lim;
 11 int hang[110],lie[110];
 12 bool pan[110][110];
 13 int S,T,SUM;
 14 struct node{
 15     int u,v,w,nxt;
 16 }g[20010];
 17 int adj[20010],e;
 18 void add(int u,int v,int w){
 19     g[e].v=v; g[e].u=u; g[e].w=w;
 20     g[e].nxt=adj[u]; adj[u]=e++;
 21 }
 22 bool Jud(){
 23     bool ok=1;
 24     for(int i=1;i<=n;i++){
 25         int he=0;
 26         for(int j=1;j<=m;j++){
 27             if(!pan[i][j]) he++;
 28         }
 29         if(he<hang[i]){ok=0;break;}
 30     }
 31     if(ok){
 32         for(int j=1;j<=m;j++){
 33             int he=0;
 34             for(int i=1;i<=n;i++){
 35                 if(!pan[i][j]) he++;
 36             }
 37             if(he<lie[j]){ok=0;break;}
 38         }
 39     }
 40     return ok;
 41 }
 42 int dep[310];
 43 bool BFS(){
 44     memset(dep,0,sizeof(dep));
 45     queue<int> q;
 46     dep[S]=1; q.push(S);
 47     int k;
 48     while(!q.empty()){
 49         k=q.front(); q.pop();
 50         for(int i=adj[k];i!=-1;i=g[i].nxt){
 51             int v=g[i].v;
 52             if(g[i].w && !dep[v]){
 53                 dep[v]=dep[k]+1;
 54                 if(v==T) return 1;
 55                 q.push(v);
 56             }
 57         }
 58     }
 59     return 0;
 60 }
 61 int dfs(int x,int fw){
 62     if(x==T) return fw;
 63     int tmp=fw,k;
 64     for(int i=adj[x];i!=-1;i=g[i].nxt){
 65         int v=g[i].v;
 66         if(g[i].w && tmp && dep[v]==dep[x]+1){
 67             k = dfs(v,min(g[i].w,tmp));
 68             if(!k){
 69                 dep[v]=0;
 70                 continue;
 71             }
 72             g[i].w-=k; g[i^1].w+=k; tmp-=k;
 73         }
 74     }
 75     return fw-tmp;
 76 }
 77 void work(){
 78     memset(adj,-1,sizeof(adj));
 79     S=0; T=110;
 80     for(int i=1;i<=n;i++) add(S,i,hang[i]), add(i,S,0);
 81     int jia=101;
 82     for(int j=1;j<=m;j++) add(j+jia,T,lie[j]), add(T,j+jia,0);
 83     for(int i=1;i<=n;i++){
 84         for(int j=1;j<=m;j++){
 85             if(pan[i][j]) continue;
 86             add(i,j+jia,1); add(j+jia,i,0);
 87         }
 88     }
 89     int he=0,tan;
 90     while(BFS()){
 91         while(tan=dfs(S,INF)) he+=tan;
 92     }
 93     printf("%d",SUM-he);
 94 }
 95 int main(){
 96     //freopen("a.in","r",stdin);
 97     //freopen("a.out","w",stdout);
 98     scanf("%d%d%d",&n,&m,&lim);
 99     for(int i=1;i<=n;i++) scanf("%d",&hang[i]), SUM+=hang[i];
100     for(int i=1;i<=m;i++) scanf("%d",&lie[i]),  SUM+=lie[i];
101     int x,y;
102     for(int i=1;i<=lim;i++){
103         scanf("%d%d",&x,&y);
104         pan[x][y]=1;
105     }
106     S=0; T=110;
107     bool ok=Jud();
108     if(!ok){
109         printf("JIONG\n");
110         return 0;
111     }
112     work();
113     return 0;
114 }

 

 

 

posted @ 2017-07-31 21:38  Nawox  阅读(164)  评论(0编辑  收藏  举报