题意:给一个无向图,求从起点到终点,和从终点到起点走过的最短路径长度,要求两次走的路径不能重复。
思路:在边上加上容量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;
}