题意:给一个n个点的带权无向图,问S到T的最短往返路径,不能重复走。
思路:可以看做S到T有两条没有重边的路径,那么原图每条边的容量为1,花费为边权,就转化为了,S到T最大流是2的时候最小费用是多少,如果最大流为1那么答案无解。
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
const int maxn = 205;
const int INF = 1e9;
using namespace std;
typedef struct ss {
int to, cap, cost, rev;
ss(int a, int b, int c, int d) {
to = a; cap = b;
cost = c; rev = d;
}
} st;
typedef pair<int, int> P;
int h[maxn], dis[maxn];
int pv[maxn], pe[maxn];
vector<st> G[maxn];
int n, m;
void init() {
for(int i = 0; i < maxn; i++) {
G[i].clear();
h[i] = 0;
}
}
void add(int f, int t, int c, int cost) {
G[f].push_back(st(t, c, cost, G[t].size()));
G[t].push_back(st(f, 0, -cost, G[f].size() - 1));
}
int mincostflow(int s, int t, int f) {
int res = 0;
while(f > 0) {
priority_queue<P, vector<P>, greater<P> > q;
q.push(P(0, s));
fill(dis, dis + maxn, INF);
dis[s] = 0;
while(!q.empty()) {
P p = q.top(); q.pop();
int l = p.first, v = p.second;
if(dis[v] < l) continue;
for(int i = 0; i < G[v].size(); i++) {
st &e = G[v][i];
///printf("cap = %d\n", e.cap);
if(e.cap > 0 && dis[e.to] > dis[v] + e.cost + h[v] - h[e.to]) {
dis[e.to] = dis[v] + e.cost + h[v] - h[e.to];
pv[e.to] = v;
pe[e.to] = i;
q.push(P(dis[e.to], e.to));
}
}
}
if(dis[t] == INF) return -1;
for(int v = 0; v < n + 2; v++) h[v] += dis[v];
int d = f;
for(int u = t; u != s; u = pv[u]) {
d = min(d, G[pv[u]][pe[u]].cap);
}
f -= d;
res += d * h[t];
for(int u = t; u != s; u = pv[u]) {
st &e = G[pv[u]][pe[u]];
e.cap -= d;
G[u][e.rev].cap += d;
}
}
return res;
}
int main() {
while(scanf("%d", &n) && n) {
init();
scanf("%d", &m);
while(m--) {
int u, v, c;
scanf("%d %d %d", &u, &v, &c);
add(u, v, 1, c);
add(v, u, 1, c);
}
add(0, 1, INF, 0);
add(n, n + 1, INF, 0);
int ans = mincostflow(0, n + 1, 2);
if(ans == -1) printf("Back to jail\n");
else printf("%d\n", ans);
}
return 0;
}