1. 程式人生 > >【網路流-最大權閉合子圖】CF1082G Petya and Graph

【網路流-最大權閉合子圖】CF1082G Petya and Graph

【題目】
原題地址
給定一幅圖,求子圖的最大權值,權值定義為邊權和-點權和。
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;
}

【總結】
水過了一天。