【最大权闭合子图】【网络流】最优价值

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/87211161

题意

在这里插入图片描述

分析:

最大权闭合子图
题解讲得非常清晰
在这里插入图片描述
在这里插入图片描述

然后,正权值是由原点连向该点,容量为该点权值。
负权值是由该点连向汇点,容量为该点的权值的相反数。

结果就是:所有正权值之和-最小割。

本题由于只有第一层权值为正,所以最优性可以保证合法性(即不会只选择后面某个子图)

建完图大概是这个样子:
在这里插入图片描述
然后就可以过了。

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 310
#define MAXM 20610
#define INF 0x3FFFFFFF
using namespace std;
char S[MAXN];
int n,s,t,A[10],B[10],id1[MAXN][MAXN],id2[MAXN],id3[10],tot;
int W[MAXN][MAXN];
vector<int> a[MAXM],rev[MAXM],w[MAXM];
void add_edge(int u,int v,int val){
	a[u].push_back(v);
	w[u].push_back(val);
	a[v].push_back(u);
	w[v].push_back(0);
	rev[u].push_back(a[v].size()-1);
	rev[v].push_back(a[u].size()-1);
}
int d[MAXM],g[MAXM];
int dfs(int f,int x){
	if(x==t)
		return f;
	int les=f;
	for(int i=0;i<int(a[x].size())&&les;i++){
		int u=a[x][i];
		if(d[u]==d[x]-1&&w[x][i]){
			int res=dfs(min(f,w[x][i]),u);
			w[x][i]-=res;
			w[u][rev[x][i]]+=res;
			les-=res;
			if(d[s]>tot)
				return f-les;
		}
	}
	if(les==f){
		g[d[x]]--;
		if(g[d[x]]==0){
			d[s]=tot+1;
			return 0;
		}
		d[x]=tot;
		for(int i=0;i<int(a[x].size());i++)
			if(w[x][i])
				d[x]=min(d[x],d[a[x][i]]);
		d[x]++;
		g[d[x]]++;
	}
	return f-les;
}
int maxflow(){
	g[0]=tot;
	int res=0;
	while(d[s]<tot)
		res+=dfs(INF,s);
	return res;
}
void init(){
	for(int i=0;i<tot;i++)
		a[i].clear(),w[i].clear(),rev[i].clear();
	memset(d,0,sizeof d);
	memset(g,0,sizeof g);
}
int main(){
	freopen("value.in","r",stdin);
	freopen("value.out","w",stdout);
	int T;
	SF("%d",&T);
	while(T--){
		init();
		SF("%d",&n);
		SF("%s",S);
		for(int i=0;i<=9;i++)
			SF("%d%d",&A[i],&B[i]);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				SF("%d",&W[i][j]);
		s=1,t=2;
		tot=3;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				id1[i][j]=i*n+j+tot;
		tot+=n*n;
		for(int i=0;i<n;i++)
			id2[i]=i+tot;
		tot+=n;
		for(int i=0;i<10;i++)
			id3[i]=i+tot;
		tot+=10;
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++){
				if(i==j)
					continue;
				add_edge(id1[i][j],id2[i],INF);
				add_edge(id1[i][j],id2[j],INF);
			}
		for(int i=0;i<n;i++)
			add_edge(id2[i],id3[S[i]-'0'],INF);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				if(i!=j)
					add_edge(s,id1[i][j],W[i][j]);
		for(int i=0;i<n;i++)
			add_edge(id2[i],t,A[S[i]-'0']);
		for(int i=0;i<10;i++){
			if(A[i]-B[i]>0)
				add_edge(s,id3[i],A[i]-B[i]);
			else
				add_edge(id3[i],t,B[i]-A[i]);
		}
		int ans=0;
		for(int i=0;i<int(a[s].size());i++)
			ans+=w[s][i];
		ans-=maxflow();
		PF("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/87211161