POJ 2135 Farm Tour 最小费用流

题意:给一个无向图,求从起点到终点,和从终点到起点走过的最短路径长度,要求两次走的路径不能重复。
思路:在边上加上容量1,费用即为路径长度,在源点和起点,终点和汇点之间加上容量为2,费用为0的边,表示走了两次,之后求最小费用

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 5005;
const int inf = 0x3f3f3f3f;
int m, n, k, vis[maxn], flow[maxn], dis[maxn], N;
struct edge {
	int rev, to, c, w;
	edge(int rev = 0, int to = 0, int c = 0, int w = 0) : rev(rev), to(to), c(c), w(w) {}
};
struct node {
	int id, pre;
	node(int id = -1, int pre = -1) : id(id), pre(pre) {}
}path[maxn];
vector<edge> g[maxn];
void addedge(int u, int v, int c, int w)
{
	g[u].push_back(edge(g[v].size(), v, c, w));
	g[v].push_back(edge(g[u].size()-1, u, 0, -w));
}
int spfa(int s, int t)
{
	memset(dis, inf, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	memset(flow, inf, sizeof(flow));
	queue<int> q;
	q.push(s); dis[s] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		vis[u] = 0;
		for (int i = 0; i < g[u].size(); i++) {
			int v = g[u][i].to, di = g[u][i].w, c = g[u][i].c;
			if (c && dis[v] > dis[u] + di) {
				dis[v] = dis[u] + di;
				path[v].id = i;
				path[v].pre = u;
				flow[v] = min(flow[u], c);
				if (!vis[v]) {
					q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
	return flow[t] != flow[s];
}
void solve(int s, int t)
{
	int maxflow = 0, mincost = 0, id, now, pre;
	while (spfa(s, t)) {
		maxflow += flow[t];
		mincost += flow[t]*dis[t];
		now = t;
		while (now != s) {
			pre = path[now].pre, id = path[now].id;
			edge &e = g[pre][id];
			e.c -= flow[t];
			g[e.to][e.rev].c += flow[t];
			now = pre;
		}
	}
	cout << mincost << endl;
}
int main()
{
	while (cin >> n >> m) {
		addedge(0, 1, 2, 0);
		for (int i = 0; i < m; i++) {
			int u, v, w;
			cin >> u >> v >> w;
			addedge(u, v, 1, w);
			addedge(v, u, 1, w);
		}
		addedge(n, n+1, 2, 0);
		solve(0, n+1);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Problem D:汽车最少费用加油行驶 Description 给定一个 N*N 的方形网格, 设其左上角坐标为 (1, 1), X 轴向右为正, Y 轴向下为正, 每个方格边长为 1, 右下角坐标为 (N, N). 一辆已装满油的汽车从 (1, 1) 为起点出发驶向终点 (N, N). 在若干个网格交叉点处设有油库供汽车在行驶途中加油, 在起点终点处不设油库. 汽车在行驶过程中遵守如下规则: 1. 只能沿网格边行驶, 装满油后能行驶 K 条网格边 2. 当行驶经过一条网格边时, 若其 X 坐标或 Y 坐标减小, 则应付费用 B, 否则免付费用 3. 在行驶过程中遇油库则应加满油并付加油费用 A 4. 在需要时可在网格点处增设油库, 并付增设油库费用 C (不含加油费用A) 上述各数中的 N, K, A, B, C 均为正整数. 求汽车从起点出发到达终点的一条所付费用最少的行驶路线所需要的费用. Input 输入数据的第一行是 N, K, A, B, C 的值, 2 ≤ N ≤ 100, 2 ≤ K ≤ 10. 第二行起是一个 N*N 的 0-1 方阵, 每行 N 个值, 至 N+1 行结束. 方阵的第 i 行第 j 列处的值为 1 表示在网格交叉点 (i, j) 处设置有一个油库, 为 0 时表示未设有油库. 各行相邻的两个数以空格分隔. Output 对于测试用例的输入数据, 在一行上输出最优行驶路线所需的费用, 即最小费用. Sample Input 9 3 2 3 6 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 Sample Output 12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值