士兵占领

题目

洛谷

做法

考虑最多能删的点

(S)向每行所代表的点连(该行最多能删的点)容量的边,每列向(T)连(同理)的边

每个存在的格子((x,y))(x)(y)(1)容量的边

My complete code

#include<bits/stdc++.h>
#include<queue>
using namespace std;
typedef int LL;
const LL maxn=1e5+9,inf=0x3f3f3f3f;
struct node{
	LL to,next,f;
}dis[maxn];
LL num,S,T,n,m,k;
LL head[309],L[109],R[109],del[109][2],lev[309];
bool visit[109][109],mark[309];
inline void Add(LL u,LL v,LL f){
	dis[++num]=(node){v,head[u],f}, head[u]=num;
}
inline LL Bfs(){
	queue<LL> que; que.push(S);
	memset(lev,0,sizeof(lev)),memset(mark,false,sizeof(mark));;
	mark[S]=true;
    while(que.size()){
    	LL u(que.front()); que.pop();
    	for(LL i=head[u];~i;i=dis[i].next){
    		LL v(dis[i].to);
    		if(!mark[v] && dis[i].f){
    			lev[v]=lev[u]+1;
    			mark[v]=true;
    			que.push(v);
			}
		}
	}return mark[T];
}
LL Dfs(LL u,LL f){
	if(u==T) return f;
	LL tmp(f),now;
	for(LL i=head[u];~i;i=dis[i].next){
		LL v(dis[i].to);
		if(tmp && dis[i].f && lev[v]==lev[u]+1){
			if(now=Dfs(v,min(tmp,dis[i].f))){
				dis[i].f-=now, dis[i^1].f+=now;
				tmp-=now;
			}else lev[v]=-1;
		}
		if(!tmp) break;
	}return f-tmp;
}
inline void Dinic(){
	LL ans(0);
	while(Bfs())
	    ans+=Dfs(S,inf);
	printf("%d",n*m-k-ans);
}
int main(){
	cin>>n>>m>>k;
	memset(head,-1,sizeof(head)), num=-1; 
	for(LL i=1;i<=n;++i) cin>>L[i];
	for(LL i=1;i<=m;++i) cin>>R[i];
	for(LL i=1;i<=k;++i){
		LL x,y; cin>>x>>y;
		visit[x][y]=true;
		++del[x][0], ++del[y][1];
	}
	for(LL i=1;i<=n;++i)
	    for(LL j=1;j<=m;++j)
	        if(!visit[i][j]){
	        	Add(i,j+n,1), Add(j+n,i,0);
			}
	S=n+m+1, T=S+1;
	for(LL i=1;i<=n;++i){
		LL now(m-del[i][0]-L[i]);
		if(now<0){
			printf("JIONG!");
			return 0;
		}
	    Add(S,i,now), Add(i,S,0);
	}
	for(LL i=1;i<=m;++i){
		LL now(n-del[i][1]-R[i]);
		if(now<0){
			printf("JIONG!");
			return 0;
		}
	    Add(i+n,T,now), Add(T,i+n,0);
	}
	Dinic();
	return 0;
}
原文地址:https://www.cnblogs.com/y2823774827y/p/10415850.html