poj 2135 最小费用最大流(从1到n往返不走重复路的最小距离)
来源:互联网 发布:超级兔子软件 编辑:程序博客网 时间:2024/05/01 01:46
题意:给定n个谷仓,有m条双向路径,每条连接两个谷仓。一个人要从1号谷仓走到n号谷仓,再从n号谷仓走回1号(来回走的路不能重复)。给定路径长度,问来回走的最短长度。
思路:由于来回可以看成2条从1到n的不同的路,所以转化为求从1到n的两条不同的路。按照最小费用流建图:假设a b之间有长度为c的路,那么ab之间费用为c,容量是1;ba之间费用为c,容量是1。(同时要建立b到a的容量为0,费用为-c的路径;也就是输入给出一条边,需要添加到邻接表中四条边)接着建立一个超级源点,连接1号景点,无费用,容量为2;同理建立一个超级汇点,连接n号景点,无费用,容量为2。
针对这道题,更新路径值的时候实际上可以断定流量只能增加1(因为每条边的流量最多为1),而且题目保证有解,进而可知spfa必执行两次,所以更新函数可以简写(见版本2)
#include <stdio.h>#include <string.h>#define N 1005#define M 10005#define min(a,b) a<b?a:b#define INF 0x3fffffffstruct edge{int x,y,cost,cap,next;}e[M*4];int n,m,top,res;int dis[N],visited[N],pre[N],q[200000],index[N],first[N];void add(int x,int y,int c,int w){e[top].y = y;e[top].cap = c;e[top].cost = w;e[top].next = first[x];first[x] = top++;e[top].y = x;e[top].cap = 0;e[top].cost = -w;e[top].next = first[y];first[y] = top++;}int spfa(){//费用当做权值,求最短路int i,front,rear,now;for(i = 0;i<=n;i++)dis[i] = INF;memset(visited,0,sizeof(visited));memset(pre,-1,sizeof(pre));front = rear = -1;q[++rear] = 0;dis[0] = 0;while(front < rear){now = q[++front];visited[now] = 0;for(i = first[now];i!=-1;i=e[i].next)if(e[i].cap && dis[e[i].y]>dis[now]+e[i].cost){dis[e[i].y] = dis[now]+e[i].cost;if(!visited[e[i].y]){visited[e[i].y] = 1;q[++rear] = e[i].y;}index[e[i].y] = i;//保存松弛的节点在邻接表中的位置pre[e[i].y] = now;}}if(dis[n]!=INF)return 1;return 0;}void sum(){int i,aug=INF;for(i = n;i!=0;i=pre[i])//得到此次增加的容量aug = min(aug,e[index[i]].cap);res += dis[n]*aug;for(i = n;i!=0;i=pre[i]){e[index[i]].cap -= aug;e[index[i]^1].cap += aug;}}int main(){freopen("a.txt","r",stdin);while(scanf("%d %d",&n,&m)!=EOF){int i,a,b,c;top = res = 0;memset(first,-1,sizeof(first));for(i = 0;i<m;i++){scanf("%d %d %d",&a,&b,&c);add(a,b,1,c);add(b,a,1,c);}add(0,1,2,0);//添加超级源点add(n,n+1,2,0);//添加超级汇点n++;while(spfa())//每求一次最短路,更新一下图的容量sum();printf("%d\n",res);}return 0;}
版本2:
#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>#include <cstdlib>using namespace std;#define INF 0x3fffffff#define N 1005#define M 40005struct edge{ int y,next,w,c;}e[M];int n,m,first[N],top,dis[N],used[N],pre[N],id[N],res;void add(int x,int y,int w,int c){ e[top].y = y; e[top].w = w; e[top].c = c; e[top].next = first[x]; first[x] = top++;}int spfa(){ int i,now; for(i = 1;i<=n+1;i++) dis[i] = INF; dis[0] = 0; queue<int> q; q.push(0); memset(used, 0, sizeof(used)); used[0] = 1; while(!q.empty()){ now = q.front(); q.pop(); used[now] = 0; for(i = first[now];i!=-1;i=e[i].next){ if(e[i].c>0 && dis[e[i].y] > dis[now]+e[i].w){ dis[e[i].y] = dis[now]+e[i].w; if(!used[e[i].y]){ used[e[i].y] = 1; q.push(e[i].y); } id[e[i].y] = i; pre[e[i].y] = now; } } } return dis[n+1]<INF;}void update(){ int i; res+=dis[n+1]; for(i = n+1;i!=0;i=pre[i]){ e[id[i]].c --; e[id[i]^1].c ++; }}int main(){ while(scanf("%d %d",&n,&m)!=EOF){ int i,a,b,w; res = top = 0; memset(first, -1, sizeof(first)); for(i = 1;i<=m;i++){ scanf("%d %d %d",&a,&b,&w); add(a,b,w,1); add(b,a,-w,0); add(b,a,w,1); add(a,b,-w,0); } add(0,1,0,2); add(1,0,0,0); add(n,n+1,0,2); add(n+1,n,0,0); while(spfa()) update(); printf("%d\n",res); } return 0;}
0 0
- poj 2135 最小费用最大流(从1到n往返不走重复路的最小距离)
- POJ 2135 最小费用最大流
- poj 2135 最小费用最大流
- poj 2135最小费用最大流模板
- 最小费用最大流模板 poj 2135
- poj 2135 (最小费用最大流)
- poj 2135最小费用最大流
- 最小费用最大流-poj-2135
- poj 2135(最小费用最大流)
- POJ 2135 最小费用最大流
- poj 2135最小费用最大流
- 最小费用最大流问题----poj 2135
- POJ-2135-最大流最小费用
- POJ 2135 最小费用最大流
- poj 2159(最小费用最大流)
- POJ 2516(最小费用最大流)
- poj 2195 (最小费用最大流)
- poj 2516(最小费用最大流)
- freemarker 整理手册
- 移动开发前端素材集锦
- jQuery的性能优化
- java 程序登陆管理平台
- oracle sqlplus 常用命令大全
- poj 2135 最小费用最大流(从1到n往返不走重复路的最小距离)
- AMD规范
- JS输出中文乱码问题解决
- python apply()函数
- Robotium学习笔记二
- 程序员使用的十大开发工具
- poj 1789 Truck History (生成树prim)
- Android_Phone源代码来电流程解读
- poj 3349 Snowflake Snow Snowflakes(hash表)