• 最小费用最大流模板


    #include "stdio.h" //poj 2135 最小费用最大流模板
    #include "string.h"
    #include <queue>
    using namespace std;
    
    #define N 1005
    #define INF 0x3fffffff
    
    struct node 
    {
    	int u,v;
    	int w,k;
    	int next;
    }edge[4*N*10];  //题目中边的条数是N的十倍,每一条边建四次!
    
    int n,m,idx,ans;
    int head[N],dis[N],route[N];
    bool mark[N];
    
    void init(); //初始化部分变量
    void EK(int start,int end);
    int SPFA(int start,int end);
    void adde(int u,int v,int w,int k);
    void addedge(int u,int v,int w,int k);
    
    
    int main()
    {
    	int i;
    	int u,v,w;
    	while(scanf("%d%d",&n,&m)!=-1)
    	{
    		init();
    		for(i=1;i<=m;i++)
    		{
    			scanf("%d %d %d",&u,&v,&w);   //对每一条边建两次,一正一反
    			adde(u,v,w,1);
    			adde(v,u,w,1);
    		}
    		int start = 0;
    		adde(start,1,0,2);  //为起点添两条边,单位流量费用为0
    		int end = n+1;
    		adde(n,end,0,2);   //为终点添两条边,单位流量费用为0
    		while( SPFA(start,end) )
    			EK(start,end);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    void init()
    {
    	ans = 0;  //结果初始化
    	idx = 0;  
    	memset(head,-1,sizeof(head));  //
    }
    
    void adde(int u,int v,int w,int k)  //对其中的一条再加上一条流量为0的回路
    {
    	addedge(u,v,w,k);
    	addedge(v,u,-w,0);
    }
    
    void addedge(int u,int v,int w,int k)  //邻接表建边
    {
    	edge[idx].u = u;
    	edge[idx].v = v;
    	edge[idx].w = w;
    	edge[idx].k = k;
    	edge[idx].next = head[u];
    	head[u] = idx;
    	idx++;
    }
    
    int SPFA(int start,int end)  //找一条存在流量的最小费用流(存在流量就行)
    {
    	int i;
    	memset(mark,false,sizeof(mark));  //初始化标记数组mark[];
    	memset(route,-1,sizeof(route));   //ruote[]记录流量路径(存下一条边的下标)
    	for(i=start;i<=end;i++)		dis[i] = INF;
    	dis[start] = 0;
    	queue<int> q;
    	q.push(start);
    	mark[start] = true;
    	int x,y;
    	while(!q.empty())
    	{
    		x = q.front();
    		for(i=head[x];i!=-1;i=edge[i].next)
    		{
    			y = edge[i].v;
    			if(edge[i].k && dis[y] > dis[x] + edge[i].w)
    			{
    				dis[y] = dis[x] + edge[i].w;
    				route[y] = i;   //route[]里面存的为边的下标
    				if(mark[y] == false)
    				{ 
    					mark[y] = true;
    					q.push(y);
    				}
    			}
    		}
    		q.pop();
    		mark[x] = false;  //对出队列的点的标记还原
    	}
    	if(dis[end] == INF) return 0;
    	return 1;
    }
    
    void EK(int start,int end)
    {
    	int x,y;
    	y = route[end];
    	//对于一般的最小费用最大流,需遍历一遍route[],求出最小费用路线上能流过的最大流量k(此题恰好为1,故此步省略!)
    	while(y!=-1)
    	{
    		x = y^1;  //很特别的处理;
    		edge[y].k--;  //对流量进行处理(正减反加)
    		edge[x].k++;
    		ans += edge[y].w;
    		y = route[edge[y].u]; //通过route[]访问路径上的下一个节点
    	}
    }
    

  • 相关阅读:
    [CF1299B] Aerodynamic
    [CF1338B] Edge Weight Assignment
    [CF689C] Mike and Chocolate Thieves
    [CF729C] Road to Cinema
    [CF735C] Tennis Championship
    [CF766C] Mahmoud and a Message
    [CF797C] Minimal string
    [CF798C] Mike and gcd problem
    [CF818D] Multicolored Cars
    《剑指Offer》面试题55:字符流中第一个不重复的字符
  • 原文地址:https://www.cnblogs.com/ruo-yu/p/4412005.html
Copyright © 2020-2023  润新知