poj2135网络流费用入门
来源:互联网 发布:软件总体设计方案 编辑:程序博客网 时间:2024/06/06 03:48
poj2135网络流费用流入门
- 题目链接:http://poj.org/problem?id=2135
题目部分
- 题意介绍:
主人公要从1号走到第N号点,再重N号点走回1号点,同时每条路只能走一次。
这是一个无向图。输入数据第一行是2个是N和M。N为点的数量,M为路径个数。
接下来M行是边的数据,每行输入3个数,边的两个端点a,b和边的长度v。
要你输出来回最短的路径长度。
题目确保存在来回的不重复路径
思路部分
这题可以转换成网络流的费用流。
来回并且路径不相同就相当于有用两条从1到N的路径。
把路径长度当成网络流里面每个流的费用,流量都设置成1这样就代表每条路径只能使用1次。增加2个点,源点和汇点,因为来回,就把源点到1建立一条流,流量为2(来回)费用为0,同样N到汇点建立一条流,流量为2费用为0。这样一个网络流就出来了。
这里费用流的增广路径是用spfa来找的,也就是找从源点到汇点流1个单位的流量最小的花费。这题找到路径后就进行正常的网络流增广路了,就是算费用的时候用+=N那个点的费用乘这个路径的最大流量
举个例子就比如坐车,要从a->g,途中要经过转车,每上一次车都要交钱,你一个人从a坐到g要花10块钱,然后你们组团一起坐车,问你一趟要花多少钱(一趟中人数是依据最小的车子能载几个人)。费用流的增广路就是这样,先找到这个路径,在看路径中的最大流量算出这条路径的费用。
用spfa不用dijkstra的原因是因为我们建立反向边的时候费用是正向边费用的负数,存在了负权值就不能用dijkstra了。
代码部分
这里输入一条边要建4条边,首先建a->b的有向边,要同时建立反向边,再建b->a的有向边,一样建立反向边。
这里node数组下标要从偶数开始用起,因为底下的增广路那块(也就是+-最小边那里)用到了 ^1 这个技巧,偶数与1异或就会加1,奇数与1异或就会减1。这样如果用正向的边,那么边的下标是偶数,对应的反向边下标就+1就可以找到,如果用的是反向边,那么边的下标是奇数,对应的正向边下标-1就可以找到。
我这里的Node结构体加了个s是这条边的起始点。
#include<iostream>#include<cstring>#include<algorithm>#include<fstream>#include<math.h>#include<algorithm>#include<stack>#include<queue>using namespace std;fstream fin("1.txt");//streambuf *buf = cin.rdbuf(fin.rdbuf());//用于重定项输入改成,把cin当成finconst int inf = 1 << 29;const int MAXN = 1010;const int MAXM = 40010;struct Node{ int s; int to; int next; int capacity; int value;};int n, m;int index;Node node[MAXM];int head[MAXN];int pre[MAXN];int dis[MAXN];bool vis[MAXN];void init(){ index = 0; memset(head, -1, sizeof(head)); memset(node, 0, sizeof(node));}void addedge(int a, int b, int v, int c){ node[index].to = b; node[index].s = a; node[index].value = v; node[index].capacity = c; node[index].next = head[a]; head[a] = index++; node[index].to = a; node[index].s = b; node[index].value = -v; node[index].capacity = 0; node[index].next = head[b]; head[b] = index++;}bool spfa(int s, int t, int nnum){ memset(vis, 0, sizeof(vis)); memset(pre, -1, sizeof(pre)); for (int i = 0; i <= nnum; i++) { dis[i] = inf; } queue<int> que; que.push(s); dis[s] = 0; vis[s] = true; while (!que.empty()) { int temp = que.front(); que.pop(); vis[temp] = false; for (int i = head[temp]; i != -1; i = node[i].next) { if (node[i].capacity) { int ne = node[i].to; if (dis[temp] + node[i].value < dis[ne]) { dis[ne] = dis[temp] + node[i].value; pre[ne] = i; if (!vis[ne]) { vis[ne] = true; que.push(ne); } } } } } if (dis[t] == inf) return false; return true;}int getMincost(int s, int t, int nnum){ int ans_flow = 0; int ans_cost = 0; int temp, minc; while (spfa(s, t, nnum)) { temp = t; minc = inf; while (pre[temp] != -1) { minc = min(node[pre[temp]].capacity, minc); temp = node[pre[temp]].s; } temp = t; while (pre[temp] != -1) { node[pre[temp]].capacity -= minc; int ss = pre[temp] ^ 1; node[ss].capacity += minc; temp = node[pre[temp]].s; } ans_cost += dis[t] * minc; } return ans_cost;}int main(){ int a, b, v; int s, t, result; while (cin >> n >> m) { init(); for (int i = 0; i < m; i++) { cin >> a >> b >> v; addedge(a, b, v, 1); addedge(b, a, v, 1); } s = n + 1; t = s + 1; addedge(s, 1, 0, 2); addedge(n, t, 0, 2); result = getMincost(s, t, t); cout << result << endl; } return 0;}
0 0
- poj2135网络流费用入门
- poj2135(最小费用最大流)
- poj2135 最小费用最大流
- POJ2135 最小费用最大流
- 最小费用最大流--poj2135
- 【POJ2135】Farm Tour 最小费用最大流
- Poj2135 Farm Tour (最小费用流)
- Poj2135 Farm Tour 最小费用流
- POJ2135(最小费用最大流)
- poj2135(简单的最小费用流问题)
- poj2135 Farm Tour 最小费用最大流
- poj2135 Farm Tour(最小费用流)
- POJ2135 Farm Tour 【最小费用最大流】
- poj2135 最小费用最大流模板
- POJ2135 Farm Tour 最小费用流
- poj2135 Farm Tour -最小费用流
- POJ2135 Farm Tour 最小费用流
- poj2135(*最小费用最大流)
- C语言基础(五)函数、多文件开发
- Ubuntu启动碰到waitting for network configuration 或者 up to 60s的问题
- 初识VR
- Java类初始化顺序
- win32 进程创建、查看和限制
- poj2135网络流费用入门
- HDU - 1358 Period(KMP next数组)
- C语言基础(六)数组
- FastCGI
- 使用API方式操作数据库
- mybatis blob 操作
- UVA31727个六边形填数a
- JS操作iframe(一)
- C语言基础(七)指针