HDU - 4289 Control 拆点最大流,领悟拆点的真谛吧!

题目链接

https://vjudge.net/problem/HDU-4289

题意

n个城市,m条路,每个城市可以花费一些钱雇佣保镖,给定起点和终点,要求起点到终点路径上必须有保镖。

思路

这道题做完让我对拆点的理解更深一步

首先题目读完第一个念头就是最小割,但是最小割是相对边来说的,而这道题是点权,那么怎么处理呢?

哎,就是拆点。拆点的用处在于将每次到达这个点的点花费改为通过拆开的两个点的边的边花费,可以实现点权到边权的一个转化。

那么具体怎么建图呢?我们将点拆成in和out,首先我们让in向out连边,权为点权。因为我们到达一个点就必须交钱,而这个钱我们通过拆点变成了in-out的边权,所以我们在处理给定的m边时就必须让他们从out出来,连接到in上,这样才能保证经过每一个点时,都完整的走了in-out这个花钱的步骤。就像我们开车自驾游,一定是从上一个城市出口到达下一个城市的入口,这样才能保证我们不会漏过城市的风景。同时注意是双向边,要建两次。

s和t已经给出,但注意给出的s是s(in),t是t(in),t并不是真正的汇点,t(out)才是真正的汇点。

代码

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
	typedef long long ll;
	const int inf=0x3f3f3f3f;
	const int maxn=1010;
	const int maxe=500010;

	int head[maxn],cnt;
	struct Edge{
    
    
		int v;
		int w;
		int next;
	}edge[maxe];

	int n,m,s,t;
	ll maxflow;
	int deep[maxn];
	int now[maxe];


	void init(){
    
    
		memset(head,-1,sizeof(head));
		cnt=0;
		maxflow=0; 
		return ;	
	}
	void add(int u,int v,int w){
    
    
		//cout<<u<<" "<<v<<" "<<w<<endl;
  		edge[cnt].v=v;
		edge[cnt].w=w;
		edge[cnt].next=head[u];
		head[u]=cnt++;
	}

	inline bool bfs(){
    
    
    	memset(deep,0x3f,sizeof(deep));
    	queue<int>q;
    	q.push(s);deep[s] = 0;now[s] = head[s];
    	while(q.size()){
    
    
        	int x = q.front();q.pop();
        	for(int i=head[x];i!=-1;i=edge[i].next){
    
    
        	    int y=edge[i].v;
         	    if(edge[i].w>0&&deep[y]==inf){
    
    
         	    	q.push(y);
        	        now[y]=head[y];
         	       	deep[y]=deep[x]+1;
        	        if(y==t)	return 1;
				}
        	}
    	}
    	return 0;
	}


	ll dfs(int x,int flow){
    
    
    	if(x==t)	return flow;
    	ll ans = 0,k,i;
    	for(i=now[x];i!=-1&&flow;i=edge[i].next){
    
    
        	now[x]=i;
        	int y=edge[i].v;
        	if(edge[i].w>0&&(deep[y]==deep[x]+1)){
    
    
        	    k=dfs(y,min(flow,edge[i].w));
         		if(!k)	deep[y]=inf;
            	edge[i].w-=k;
            	edge[i^1].w+=k;
            	ans+=k;
            	flow-=k;
        	}
    	}
    	return ans;
	}	

	void dinic(){
    
    
    	while(bfs())
    	    maxflow+=dfs(s,inf);
	}

	int main(){
    
    	
		IOS
		while(cin>>n>>m>>s>>t){
    
    
			t+=205;
			init();
			for(int i=1;i<=n;i++){
    
    
				int cost;
				cin>>cost;
				add(i,i+205,cost);
				add(i+205,i,0);
			}
			while(m--){
    
    
				int u,v;
				cin>>u>>v;
				add(u+205,v,inf);
				add(v,u+205,0);
				add(v+205,u,inf);
				add(u,v+205,0);
			}
			dinic();
	    	cout<<maxflow<<endl;
		}
    	return 0;
	}

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/108344520
今日推荐