P4311 士兵占领[最大流]
Posted saigyouji-yuyuko
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4311 士兵占领[最大流]相关的知识,希望对你有一定的参考价值。
有一个$M * N$的棋盘,有的格子是障碍。现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵。我们称这些士兵占领了整个棋盘当满足第i行至少放置了$L_i$个士兵, 第j列至少放置了$C_j$个士兵。现在你的任务是要求使用最少个数的士兵来占领整个棋盘。
考虑到说棋盘问题,选的行和列之间是有关联的,彼此制约着数量,就应该可以从网络流入手(然而如果我不是奔网络流刷题来的说不定会瞎写一发dp)
最小化答案,应该对应的是最大流的反向转化(也就是化加为减,求减数最大值,如最小路径覆盖),要不然就是最小割。反正这题辣鸡我是想了一会最小割没想出来才去转化问题的。最少要摆多少个,可以看成把棋盘能摆满的都摆满,再去删去没必要的点。这样的话构建二分图,左点集表示每行,右点集是列。s点向左点集连边容量为$n-L_i-x$ x表示本行障碍数量。容量意思就是我这行最多可以删??那么多点,再删就不合要求啦。右点集同理。$(x,y)$无障碍就在左右点集间连边容量为1,这样一条s到t的通路就是删除一个点$(x,y)$,然后做最大流后用总空格数减最大流即答案。
哦对了记得特判啊。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef pair<int,int> pii; 5 template<typename T>inline char MIN(T&A,T B){return A<B?A=B,1:0;} 6 template<typename T>inline char MAX(T&A,T B){return A>B?A=B,1:0;} 7 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 8 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 9 template<typename T>inline T read(T&x){ 10 x=0;char c;while(!isdigit(c=getchar()))if(isalpha(c))return x=(int)c; 11 while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return x; 12 } 13 const int N=200+7,M=10400+7,INF=0x3f3f3f3f; 14 int w[M<<1],v[M<<1],Next[M<<1],Head[N<<1],cur[N<<1],dis[N<<1],tot=1,s,t,n,m; 15 inline void Addedge(int x,int y,int z){ 16 v[++tot]=y,Next[tot]=Head[x],Head[x]=tot,w[tot]=z; 17 v[++tot]=x,Next[tot]=Head[y],Head[y]=tot,w[tot]=0; 18 } 19 #define y v[j] 20 inline char bfs(){ 21 queue<int> q;q.push(s),memset(dis,0,sizeof dis),dis[s]=1; 22 for(register int i=1;i<=m+n+2;++i)cur[i]=Head[i]; 23 while(!q.empty()){ 24 int x=q.front();q.pop(); 25 for(register int j=Head[x];j;j=Next[j])if(w[j]&&!dis[y]){ 26 dis[y]=dis[x]+1,q.push(y); 27 if(y==t)return 1; 28 } 29 } 30 return 0; 31 } 32 int dinic(int x,int flow){ 33 if(!flow||x==t)return flow; 34 int rest=flow,k; 35 for(register int j=cur[x];j&&rest;cur[x]=j,j=Next[j])if(w[j]&&dis[y]==dis[x]+1){ 36 if(!(k=dinic(y,_min(rest,w[j]))))dis[y]=0; 37 rest-=k,w[j]-=k,w[j^1]+=k; 38 } 39 return flow-rest; 40 } 41 #undef y 42 int a[N][N]; 43 int x,y,k,res,cnt; 44 45 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout); 46 read(n),read(m),read(k);s=n+m+1,t=s+1; 47 for(register int i=1;i<=n;++i)read(a[i][0]),a[i][0]=m-a[i][0]; 48 for(register int i=1;i<=m;++i)read(a[0][i]),a[0][i]=n-a[0][i]; 49 for(register int i=1;i<=k;++i)read(x),read(y),--a[x][0],--a[0][y],a[x][y]=1; 50 for(register int i=1;i<=_max(n,m);++i)if(a[i][0]<0||a[0][i]<0){printf("JIONG! ");return 0;} 51 for(register int i=1;i<=n;++i)Addedge(s,i,a[i][0]); 52 for(register int i=n+1;i<=n+m;++i)Addedge(i,t,a[0][i-n]); 53 for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)if(!a[i][j])Addedge(i,j+n,1),++cnt; 54 while(bfs())res+=dinic(s,INF); 55 printf("%d ",cnt-res); 56 return 0; 57 }
以上是关于P4311 士兵占领[最大流]的主要内容,如果未能解决你的问题,请参考以下文章