P4313

先只考虑单个人,则把 \(S\rightarrow i\) 的容量设为 \(a_i\),把 \(i\rightarrow T\) 的容量设为 \(b_i\)
显然一个人不能同时选两类,所以他需要选一类割掉,所以是最小割。
然后我们考虑以下模型:
\(X\) 集合内所有点都选择了 \(A\)(把 \(B\) 的边割掉了),则能获得 \(x\) 贡献。
此时我们建一个虚点 \(u\),将 \(u\)\(A\) 以一条容量为 \(x\) 的边相连,现在我们要在 \(X\) 中任意一点被割时强制要求他把这条边也割了。
我们为 \(u\)\(X\) 中的所有点连上容量为 \(\infty\) 的边。由于不可能割掉 \(\infty\),只能把 \(x\) 这条边割掉。
答案即为没有被割掉的边权和。(除了 \(\infty\)

#include<bits/stdc++.h>
#define int long long
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const int N=3e4+5;
const int MM=N*5;
const int inf=1e9;
int n,m;
int a[N][4];
int f(int x,int y){
	return (x-1)*m+y;
}
bool sf(int x,int y){
	if(x<1||n<x||y<1||m<y)return 0;
	return 1;
}
int xx[4]={-1,0,1,0};
int yy[4]={0,1,0,-1};
struct edge{
	int v,w,nxt;
}e[MM*2];
int ec=1,hd[N];
void add(int u,int v,int w){
	e[++ec]={v,w,hd[u]};
	hd[u]=ec;
}
int S,T;
int dis[N],cur[N];
void bfs(int st){
	rep(i,1,T){
		dis[i]=0;
		cur[i]=hd[i];
	}
	queue<int>q;
	q.push(st);
	dis[st]=1;
	int u;
	while(q.size()){
		u=q.front();
		q.pop();
		for(int i=hd[u];i;i=e[i].nxt){
			if(e[i].w&&!dis[e[i].v]){
				dis[e[i].v]=dis[u]+1;
				q.push(e[i].v);
			}
		}
	}
}
int dfs(int u,int flw){
	if(u==T){
		return flw;
	}
	int res=0,tmp;
	for(int &i=cur[u];i&&flw;i=e[i].nxt){
		if(e[i].w&&dis[e[i].v]==dis[u]+1){
			tmp=dfs(e[i].v,min(flw,e[i].w));
			res+=tmp;
			flw-=tmp;
			e[i].w-=tmp;
			e[i^1].w+=tmp;
		}
	}
	return res;
}
int dinic(){
	int res=0,tmp;
	while(1){
		bfs(S);
		tmp=dfs(S,inf);
		if(!tmp){
			break;
		}
		res+=tmp;
	}
	return res;
}
signed main(){
	scanf("%lld %lld",&n,&m);
	int sum=0;
	rep(k,0,3){
		rep(i,1,n){
			rep(j,1,m){
				scanf("%lld",&a[f(i,j)][k]);
				sum+=a[f(i,j)][k];
			}
		}
	}
	S=n*m*3+1;
	T=S+1;
	rep(i,1,n){
		rep(j,1,m){
			add(S,f(i,j),a[f(i,j)][0]);
			add(f(i,j),S,0);
			add(f(i,j),T,a[f(i,j)][1]);
			add(T,f(i,j),0);
			add(S,f(i,j)+n*m,a[f(i,j)][2]);
			add(f(i,j)+n*m,S,0);
			add(f(i,j)+n*m*2,T,a[f(i,j)][3]);
			add(T,f(i,j)+n*m*2,0);
			add(f(i,j)+n*m,f(i,j),inf);
			add(f(i,j),f(i,j)+n*m,0);
			add(f(i,j),f(i,j)+n*m*2,inf);
			add(f(i,j)+n*m*2,f(i,j),0);
			rep(p,0,3){
				if(sf(i+xx[p],j+yy[p])){
					add(f(i,j)+n*m,f(i+xx[p],j+yy[p]),inf);
					add(f(i+xx[p],j+yy[p]),f(i,j)+n*m,0);
					add(f(i+xx[p],j+yy[p]),f(i,j)+n*m*2,inf);
					add(f(i,j)+n*m*2,f(i+xx[p],j+yy[p]),0);
				}
			}
		}
	}
	printf("%d\n",sum-dinic());
	return 0;
}
posted @ 2024-07-16 19:46  ax_by_c  阅读(16)  评论(0)    收藏  举报