[BZOJ 1458]士兵占领(网络流)
Posted Zars19
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 1458]士兵占领(网络流)相关的知识,希望对你有一定的参考价值。
Description
有一个M * N的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了Li个士兵, 第j列至少放置了Cj个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。
Solution
可以用上下界最小流来做,不过我觉得黄学长的这个思路也很直接
将每行每列都看成一个点,由s向行连边,容量为可以放置的士兵数-至少放置的士兵数
由列向t连边,容量为可以放置的士兵数-至少放置的士兵数
然后对于每个无障碍的点,由行向列连流量为1的边
这样跑最大流就可以得到最多可以删去多少个士兵啦
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<queue> #define INF 0x3f3f3f3f #define MAXN 105 using namespace std; int s,t,m,n,k,l[MAXN],c[MAXN],la[MAXN],ca[MAXN],level[MAXN*3],head[MAXN*3],cnt=0; bool f[MAXN][MAXN]; struct Node { int next,to,cap; }Edges[MAXN*MAXN*4]; int read() { int x=0,f=1;char c=getchar(); while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } void addedge(int u,int v,int w) { Edges[cnt].next=head[u]; head[u]=cnt; Edges[cnt].to=v,Edges[cnt++].cap=w; } void insert(int u,int v,int w) { addedge(u,v,w); addedge(v,u,0); } queue<int>q; bool bfs() { memset(level,-1,sizeof(level)); q.push(s),level[s]=0; while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];~i;i=Edges[i].next) { int v=Edges[i].to; if(level[v]==-1&&Edges[i].cap) level[v]=level[u]+1,q.push(v); } } if(level[t]==-1)return false; return true; } int dfs(int u,int f) { if(u==t)return f; int flow=0,d; for(int i=head[u];~i&&flow<f;i=Edges[i].next) { int v=Edges[i].to; if(level[v]==level[u]+1&&Edges[i].cap) { d=dfs(v,min(f-flow,Edges[i].cap)); flow+=d; Edges[i].cap-=d; Edges[i^1].cap+=d; } } if(!flow)level[u]=-1; return flow; } int dinic() { int res=0,d; while(bfs()) { while(d=dfs(s,INF)) res+=d; } return res; } int main() { memset(head,-1,sizeof(head)); m=read(),n=read(),k=read(); s=0,t=m+n+1; for(int i=1;i<=m;i++)l[i]=read(),la[i]=n; for(int i=1;i<=n;i++)c[i]=read(),ca[i]=m; for(int i=1;i<=k;i++) { int x=read(),y=read(); la[x]--,ca[y]--; if(la[x]<l[x]||ca[y]<c[y]){printf("JIONG!\n");return 0;} f[x][y]=1; } for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(!f[i][j])insert(i,m+j,1); for(int i=1;i<=m;i++)insert(s,i,la[i]-l[i]); for(int i=1;i<=n;i++)insert(m+i,t,ca[i]-c[i]); printf("%d\n",m*n-k-dinic()); return 0; }
以上是关于[BZOJ 1458]士兵占领(网络流)的主要内容,如果未能解决你的问题,请参考以下文章