BZOJ 1458 士兵占领

Posted GFY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1458 士兵占领相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=1458

题意:n x m的棋盘,k个位置不能放,每行和每列都有要求至少的士兵,求能否有最少的满足条件的士兵放法是多少。

思路:先全放满求能否满足,再尽量删掉士兵:

对于每行:能放m[i],至少放c[i],就从S连向i:m[i]-c[i],代表能删的最大

对于每列:能放m[i],至少放c[i],就从i+n连向T:m[i]-c[i],代表能删的最大   

这样对于i,j这个位置如果可以放士兵,那就从i行连向j+n,流量为1,共享删掉1个

求最大流,就等于最小割,得到的就是能删的最多,然后答案就是Σm1[i]-最大流

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define inf 0x7fffffff
 7 int tot,go[200005],next[200005],flow[200005],first[200005];
 8 int op[200005],nodes,T,S,dis[200005],cnt[200005],pd[105][105],n,m,k;
 9 int m1[200005],m2[200005],c1[200005],c2[200005];
10 int read(){
11     int t=0,f=1;char ch=getchar();
12     while (ch<0||ch>9){if (ch==-) f=-1;ch=getchar();}
13     while (0<=ch&&ch<=9){t=t*10+ch-0;ch=getchar();}
14     return t*f;
15 }
16 void insert(int x,int y,int z){
17     tot++;
18     go[tot]=y;
19     next[tot]=first[x];
20     first[x]=tot;
21     flow[tot]=z;
22 }
23 void add(int x,int y,int z){
24     insert(x,y,z);op[tot]=tot+1;
25     insert(y,x,0);op[tot]=tot-1;
26 }
27 int dfs(int x,int f){
28     if (x==T) return f;
29     int mn=nodes,sum=0;
30     for (int i=first[x];i;i=next[i]){
31         int pur=go[i];
32         if (flow[i]&&dis[pur]+1==dis[x]){
33             int save=dfs(pur,std::min(f-sum,flow[i]));
34             flow[i]-=save;
35             flow[op[i]]+=save;
36             sum+=save;
37             if (sum==f||dis[S]>=nodes) return sum;
38         }
39         if (flow[i]) mn=std::min(mn,dis[pur]);
40     }
41     if (sum==0){
42         cnt[dis[x]]--;
43         if (cnt[dis[x]]==0){
44             dis[S]=nodes;
45         }else{
46             dis[x]=mn+1;
47             cnt[dis[x]]++;
48         }
49     }
50     return sum;
51 }
52 int main(){
53     n=read();m=read();k=read();
54     S=0,T=n+m+1;nodes=T+1;
55     int sum1=0,sum2=0;
56     for (int i=1;i<=n;i++){
57         int x=read();
58         sum1+=x;
59         m1[i]=x;
60     }
61     for (int i=1;i<=m;i++){
62         int x=read();
63         sum2+=x;
64         m2[i]=x;
65     }
66     for (int i=1;i<=k;i++){
67         int x=read(),y=read();
68         pd[x][y]=1;
69     }
70     int ans=0;
71     for (int i=1;i<=n;i++)
72      for (int j=1;j<=m;j++)
73       if (!pd[i][j])
74        c1[i]++,c2[j]++;
75     int sx=0;
76     for (int i=1;i<=n;i++)
77      sx+=c1[i];   
78     for (int i=1;i<=n;i++)
79      if (c1[i]<m1[i]) {
80             printf("JIONG!\n");return 0;
81      }   
82      for (int i=1;i<=m;i++)
83       if (c2[i]<m2[i]){
84             printf("JIONG!\n");return 0;
85       }
86     for (int i=1;i<=n;i++)
87      add(S,i,c1[i]-m1[i]);
88     for (int i=1;i<=m;i++)
89      add(i+n,T,c2[i]-m2[i]);   
90     for (int i=1;i<=n;i++)
91      for (int j=1;j<=m;j++)
92       if (!pd[i][j])
93        add(i,j+n,1);       
94     while (dis[S]<nodes) ans+=dfs(S,inf); 
95     ans=sx-ans;
96     printf("%d\n",ans);  
97 }

 

以上是关于BZOJ 1458 士兵占领的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1458: 士兵占领 -- 最大流

BZOJ-1458士兵占领 最大流

bzoj1458: 士兵占领 网络流

bzoj1458士兵占领

bzoj 1458: 士兵占领

BZOJ1458: 士兵占领