【网络流-最大权闭合子图】CF1082G Petya and Graph

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/84640108

【题目】
原题地址
给定一幅图,求子图的最大权值,权值定义为边权和-点权和。
n , m 1 0 3 n,m\leq 10^3 ,边权 1 0 9 \leq 10^9

【解题思路】
十分经典的最小割建图。
对于每个点 ( i d , w ) (id,w) ,连 ( S , i d , w ) (S,id,w) ,对于一条边 ( i d , u , v , w ) (id,u,v,w) ,连 ( u , i d , I N F ) ( v , i d , I N F ) ( i d , T , w ) (u,id,INF)(v,id,INF)(id,T,w)
用所有边权和减去最小割即可。

考虑为什么是对的?实际上就相当于对一条边限制了选择它的两个端点得到边权,或者放弃边权。

【参考代码】

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=2e3+10,INF=0x3f3f3f3f;
int n,m,tot,S,T;
int head[N],cur[N],dis[N];
ll ans;
queue<int>q;

int read()
{
	int ret=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return ret;
}

struct Tway{int v,w,nex;}e[N<<3];
void add(int u,int v,int w)
{
	e[++tot]=(Tway){v,w,head[u]};head[u]=tot;
	e[++tot]=(Tway){u,0,head[v]};head[v]=tot;
}

bool bfs()
{
	memcpy(cur,head,sizeof(head));
	memset(dis,-1,sizeof(dis)); 
	while(!q.empty()) q.pop();

	q.push(S);dis[S]=0;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].v;
			if(!~dis[v] && e[i].w) dis[v]=dis[x]+1,q.push(v);
		}
	}
	return ~dis[T];
}

int dfs(int x,int flow)
{
	if(x==T || !flow) return flow;
	int f,used=0;
	for(int &i=cur[x];i;i=e[i].nex)
	{
		int v=e[i].v;
		if(dis[v]!=dis[x]+1 || !(f=dfs(v,min(flow-used,e[i].w)))) continue;
		e[i].w-=f;e[i^1].w+=f;used+=f;
		if(used==flow) break;
	}
	return used;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("CF1082G.in","r",stdin);
	freopen("CF1082G.out","w",stdout);
#endif
	n=read();m=read();S=0;T=n+m+1;tot=1;
	for(int i=1;i<=n;++i) add(S,i,read());
	for(int i=1;i<=m;++i)
	{
		int u=read(),v=read(),w=read();
		add(u,i+n,INF);add(v,i+n,INF);add(i+n,T,w);
		ans+=w;
	}
	while(bfs()) ans-=dfs(S,INF);
	printf("%lld\n",ans);

	return 0;
}

【总结】
水过了一天。

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/84640108
今日推荐