邻接表--建图、spfa、EK算法 (转化为最小费用最大流)

原创 2015年05月31日 10:10:44
<pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#include <queue>
#include <vector>         
#define inf 1<<30     //poj2135(邻接表--建图、spfa、EK算法)      
#define N 1010
using namespace std;
/*
总结:
邻接表相对于邻接矩阵要好得多,一方面它不用考虑是否会重边,因为在下面的操作下会在重边的情况下取得最佳的结果,另一方面它相对于邻接矩阵要节省空间
另外,要注意邻接表的数组要开大点
*/
struct Edge
{
	int u, v, w, cap, next;    //使用邻接表,u表示起点,v表示终点,w表示费用(相当于最短路),cap表示容量
}edge[50010];   //注意,邻接表的数组要开大点
int n, m, index, pre[N], dis[N], vis[N], p[N];
queue<int> q;
void add(int a, int b, int k, int c)
{
	edge[index].u=a;
	edge[index].v=b;
	edge[index].w=c;
	edge[index].cap=k;
	edge[index].next=pre[a];
	pre[a]=index++;
	edge[index].u=b;
	edge[index].v=a;
	edge[index].w=-c;  //注意,同条线段相反方向权值为-c,容量为0
	edge[index].cap=0;
	edge[index].next=pre[b];
	pre[b]=index++;
	return ;
}	
void init()  //构图  
{
	int a, b, c;
	memset(pre, -1, sizeof(pre));
	while(m--)
	{
		scanf("%d%d%d", &a, &b, &c);//注意这里的线段是双向的
		add(a, b, 1, c);   //一条线段就要上面的两个操作
		add(b, a, 1, c); 
	}
	add(0, 1, 2, 0); //以下建立超级源点0和超级汇点n+1,其他点从1开始
	add(n, n+1, 2, 0);
	return ;
}
int mpmf()
{
	int t, s=0, flow, totprice=0, g=n+1, u;
	while(!q.empty())
		q.pop();	
	while(1)    //spfa算法
	{
		for(t=0; t<=g; ++t)
		{
			dis[t]=inf;
			vis[t]=0;
		}
		dis[s]=0;    //注意起点不能改变
		vis[s]=1;
		q.push(s);
		while(!q.empty())
		{
			u=q.front();
			q.pop();
			vis[u]=0;
			for(t=pre[u]; t!=-1; t=edge[t].next)
			{
				if(edge[t].cap&&dis[edge[t].v]>dis[u]+edge[t].w)
				{
					dis[edge[t].v]=dis[u]+edge[t].w;
					p[edge[t].v]=t;  //这里记录的方法和邻接矩阵不同,记录的是尾点在edge数组的位置
					if(!vis[edge[t].v])
					{
						vis[edge[t].v]=1;
						q.push(edge[t].v);
					}
				}
			}
		}
		if(dis[g]==inf)
			break;
		for(t=g, flow=inf; t!=s; t=edge[p[t]].u)  //取线路中的最小流量
		{
			if(edge[p[t]].cap<flow)
				flow=edge[p[t]].cap;  
		}
		for(t=g; t!=s; t=edge[p[t]].u)   //更新流量
		{
			edge[p[t]].cap-=flow;
			edge[p[t]^1].cap+=flow;
		}
		totprice+=dis[g]*flow;  //最小费用最大流
	}
	return totprice;
}

int main()
{
	while(scanf("%d%d", &n, &m)!=EOF)
	{
		index=0;
		init();  //初始化邻接表
		printf("%d\n", mpmf());
	}
	return 0;
}





            
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

poj 2135 Farm Tour--最小费用最大流--邻接表--构图的时候注意退边--以及退边的算法

/* 题意:n个地点有m条路相连,从1走到n再回来,不走重复的路(这题居然认为,同一条路,按不同的方向走算是走不重复的路) 最小费用最大流 因为要来回,素以相当于找两条1~n的最短路 s~1 流量...

poj 2135 最小费用最大流 EK+SPFA

传送门 题意:n个点m条边,从1出发到n,再从n返回1,不走重复的边,求路程最少是多少。 个人心得:无向图的网络流,一开始对于建双边还心存不解,后来想着想着就想明白了,明白了就好。 思路:能从1...

最小费用最大流 spfa() + ek()

/** 一个多月没碰,感觉忘完了…… 最小费就是有多条路可以满足最大流量的情况下所需要的最小费用 把费用改成相反数或改下spfa()的松弛就可最大费了 比如:从北京...
  • zcube
  • zcube
  • 2015-09-05 10:00
  • 2330

【最小费用最大流+邻接表】POJ 2135

因为有两条不同路径,所以可以这样构图:超级源点s->1,容量为2,边权为0,n->超级汇点t,容量为2,边权为0,其他的点容量为1,边权是输入的数据,这样就保证了肯定有两条不同的路径,而且模型肯定满流...

HDU 1533 (最小费用最大流)(spfa+ek或spfa+dinic)

HDU 1533 (最小费用最大流)(spfa+ek或spfa+dinic) 设一个虚拟source和sink,source连man,费用为0,home连sink,费用为0,与source和sink连...

HDU 3549 最大流 EK算法 邻接表实现

EK就是BFS不断地找增广路,知道找不到为止,复杂度O(VE^2)  把边开小了 结果还回TLE 查了半天没查出来,边开成2倍就过了   #include #include #include #...

最小费用最大流(邻接矩阵和邻接表)

邻接矩阵: var t,ii,i,j,n,cost,top,tail,min,tt,ttf:longint; pre,d:array[1..1000]of longint; b:arr...

网络流入门 最大流,带下界,最小费用,EK算法,Dinic算法 模板

网络流题目内容有最大流,最小费用,匹配等 基础的是最大流问题,核心在于添加了反向边,让程序有修订的可能 在有向图中边的权值一般+=,因为可能有多条路。 正向边的数值为可以通过的最大量,反向同义。 ...

【图论】最大流之EK算法与Dinic算法及最小费用最大流

最大流: 给出一张网络图,并指定源点和终点,每条边都有它的容量,起点有着无限的流量,求从源点到经过的所有路径的最终到达汇点的最大流量和。对于同一个节点,流入的流量之和和流出的流量之和相同,即假如结点1...

hdu3549 Flow Problem 网络最大流的三种写法(Ek,Dinic(邻接矩阵,邻接表),Isap)

初学网络流,用的是小白书上面的EK算法模板,自己看别人的博客理解了一发,在这里存个模板。hdu3549 Flow Problem (网络最大流EK算法)#include #include #inclu...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)