2018寧夏邀請賽 Clever King(最大點權閉合子圖學習+模板)

參考博客:https://www.cnblogs.com/dilthey/p/7565206.html

題意:T組樣例。n種產品,m個礦場。製造每種產品都需要一些其他產品和礦石。製造一種產品會獲得val的收益,開採一個礦場需要花費cost,礦場一旦開採就能獲得無窮多的礦石。問淨收益的最大值。

結論:

1、最大點權閉合子圖的值等於正點權和-最小割。

2、最大點權閉合子圖中的節點的後繼節點都在該子圖中。

 思路:正權點和源點連邊容量爲權值,負權點和匯點連邊容量也爲權值,爲相反數也就是正的,其餘邊容量都爲inf。跑一遍最大流後,用正權和減去最大流即可。

#include <bits/stdc++.h>
#define  ll long long
#define int long long
using namespace std;
const int N = 1e3+10;
const int M = 1e6+10;
const int inf = 0x3f3f3f3f3f3f3f3fLL;
struct node
{
	int  to,ca,next;
}g[M];
int head[N],deep[N],cur[N],q[N],he,ta,cnt,a[210],b[210];
int n,m,s,t;
void Init()
{
	cnt=0;
	memset(head,-1,sizeof(head));
	//for(int i=1;i<=n;i++)
		//head[i]=-1;
	return ;
}
void add(int u,int v,int w)
{
	g[cnt].to=v;
	g[cnt].ca=w;
	g[cnt].next=head[u];
	head[u]=cnt++;
	return ;
}
bool bfs()
{
	memset(deep,0,sizeof(deep));
	//for(int i=1;i<=n;i++)
		//deep[i]=0;
	he=ta=0;
	int u,v;
	q[ta++]=s;
	deep[s]=1;//別漏了!!!!!!!!!!!!!!!! 
	while(he!=ta)
	{
		u=q[he++];
		//cout<<u<<endl;
		if(u==t) return 1;
		for(int i=head[u];i!=-1;i=g[i].next)
		{
			v=g[i].to;
			if(g[i].ca>0&&!deep[v])
			{
				deep[v]=deep[u]+1;
				q[ta++]=v;
			}
		}
	}
	return deep[t]!=0;
}
int dfs(int u,int flow)
{
	//cout<<u<<endl;
	if(u==t||!flow) return flow;
	int ans=0,nowflow,v;
	for(int& i=cur[u];i!=-1;i=g[i].next)
	{
		v=g[i].to;
		if(g[i].ca>0&&deep[v]==deep[u]+1)
		{
			nowflow=dfs(v,min(flow,g[i].ca));
			if(nowflow)
			{
				ans+=nowflow;
				flow-=nowflow;
				g[i].ca-=nowflow;
				g[i^1].ca+=nowflow;
				if(!flow) break;
			}	
		}
	}
	if(!ans) deep[u]=0;
	return ans;
}
int Dinic()
{
	int maxflow=0,flow;
	while(bfs())
	{
		memcpy(cur,head,sizeof(head));
		//for(int i=1;i<=n;i++)
			//cur[i]=head[i];
		while(flow=dfs(s,inf))
		{
			//cout<<flow<<endl;
			maxflow+=flow;
		}
			
	}
	//cout<<maxflow<<endl;
	return maxflow;
}
signed main(void)
{
	int T;
	scanf("%lld",&T);
	while(T--)
	{
		int sum=0;
		
		scanf("%lld%lld",&n,&m);
		s=0,t=n+m+1;
		Init();
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			sum+=a[i];
			add(s,i,a[i]);
			add(i,s,0);
		}
		for(int i=1;i<=m;i++)
		{
			scanf("%lld",&b[i]);
			add(i+n,t,b[i]);
			add(t,i+n,0);
		}
		for(int i=1;i<=n;i++)
		{
			int k1,k2,x;
			scanf("%lld%lld",&k1,&k2);
			for(int j=1;j<=k1;j++)
			{
				scanf("%lld",&x);
				add(i,x+n,inf);
				add(x+n,i,0);
			}
			for(int j=1;j<=k2;j++)
			{
				scanf("%lld",&x);
				add(i,x,inf);
				add(x,i,0);
			}
		}
		
		printf("%lld\n",sum-Dinic());	
	}
	
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章