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 }