bzoj 1458: 士兵占领

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:
首先 JIONG! 很好判断的:如果某一行/列的 要求数>行/列总数-障碍数,则是 JIONG!
由于 横行只能放Li个  竖行只能放Ci个 
源点S 向各横行连边,容量为Li
汇点T 向各竖行连边,容量为Ci  (因为不是JIONG!,一定能放下,所以限制最少)
如果横行和竖行交点无障碍,连一条容量为 1 的边
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define mem(a,b) memset(a,b,sizeof(a))
  5 using namespace std;
  6 const int INF=(1<<31)-1;
  7 inline int minn(int a,int b){return a<b?a:b;}
  8 struct son
  9 {
 10     int u,v,next,w;
 11 }a1[500001];
 12 int first[500001],e;
 13 
 14 void addbian(int u,int v,int w)
 15 {
 16     a1[e].v=v;
 17     a1[e].u=u;
 18     a1[e].w=w;
 19     a1[e].next=first[u];
 20     first[u]=e++;
 21 }
 22 
 23 int ji[501][501];
 24 int n,m,k;
 25 int u,o;
 26 int num1[501],num2[501];
 27 int heng[501],shu[501];
 28 int sum,ans;
 29 int S,T;
 30 int dep[1001];
 31 
 32 int dui[1000001],he,en;
 33 inline void clear(){he=1;en=0;}
 34 inline bool empty(){return en>=he?0:1;}
 35 inline void push(int x){dui[++en]=x;}
 36 inline void pop(){++he;}
 37 inline int top(){return dui[he];}
 38 
 39 int bfs()
 40 {
 41     mem(dep,0);
 42     clear();
 43     dep[S]=1;push(S);
 44     while(!empty())
 45     {
 46         int now=top();pop();
 47         for(int i=first[now];i!=-1;i=a1[i].next)
 48         {
 49             int temp=a1[i].v;
 50             if(dep[temp]||!a1[i].w)continue;
 51             dep[temp]=dep[now]+1;
 52             push(temp);
 53             if(temp==T)return 1;
 54         }
 55     }
 56     return 0;
 57 }
 58 
 59 int dfs(int x,int val)
 60 {
 61     if(x==T)return val;
 62     int val2=val,k;
 63     for(int i=first[x];i!=-1;i=a1[i].next)
 64     {
 65         int temp=a1[i].v;
 66         if(dep[temp]!=dep[x]+1||!a1[i].w||!val2)continue;
 67         k=dfs(temp,minn(val2,a1[i].w));
 68         if(!k){dep[temp]=0;continue;}
 69         a1[i].w-=k;a1[i^1].w+=k;val2-=k;
 70     }
 71     return val-val2;
 72 }
 73 
 74 int Dinic()
 75 {
 76     int ans=0;
 77     while(bfs())
 78       ans+=dfs(S,INF);
 79     return ans;
 80 }
 81 
 82 int main(){
 83     int flag=0;
 84     mem(first,-1);
 85     scanf("%d%d%d",&n,&m,&k);
 86     S=0;T=n+m+1;
 87     for(int i=1;i<=n;++i)
 88     {scanf("%d",&heng[i]);sum+=heng[i];}
 89     for(int i=1;i<=m;++i)
 90     {scanf("%d",&shu[i]);sum+=shu[i];}
 91     
 92     for(int i=1;i<=k;++i)
 93     {scanf("%d%d",&u,&o);ji[u][o]=1;++num1[u];++num2[o];}
 94     
 95     for(int i=1;i<=n;++i)if(m-num1[i]<heng[i])flag=1;
 96     for(int i=1;i<=m;++i)if(n-num2[i]<shu[i])flag=1;
 97     
 98     for(int i=1;i<=n;++i)
 99       for(int j=1;j<=m;++j)
100         if(!ji[i][j]){addbian(i,j+n,1);addbian(j+n,i,0);}
101     
102     for(int i=1;i<=n;++i)
103     {addbian(S,i,heng[i]);addbian(i,S,0);}
104     for(int i=n+1;i<=n+m;++i)
105     {addbian(i,T,shu[i-n]);addbian(T,i,0);}
106     
107     int hh=Dinic();
108     if(flag)
109       printf("JIONG!");
110     else
111       printf("%d",sum-hh);
112     //while(1);
113     return 0;
114 }
code

 

posted @ 2017-07-30 06:22  A_LEAF  阅读(157)  评论(0编辑  收藏  举报