题意:给出1~n点和m条无向边,要求从1走到n再从n回到1处的最小费用,要求每条边走过不超过1次
题解:可转换为求从1到n的流量f=2的最小费用流问题(不可先从左到右扫一遍最短路再删去使用过的边最后再次最短路回起点,只做到局部最优而非全局)最小费用最大流(Dijkstra+最大流算法)O(F|E|log|V|)或O(F|V|^2)
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<functional>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = (int)2e5 + 50;
typedef pair<int, int>P; //first->最短路距离 second->顶点编号
struct edge {
int to, cap, cost, rev;
};
int V;//顶点数
vector<edge>G[maxn];
int h[maxn]; //顶点的势,用来避免负环的出现
int dist[maxn];//最短距离
int prevv[maxn], preve[maxn];//最短路的前驱结点和对应的边
void add(int from, int to, int cap, int cost) {
edge ee;
ee.to = to, ee.cap = cap, ee.rev = G[to].size(), ee.cost = cost;
G[from].push_back(ee);
ee.to = from, ee.cap = 0, ee.rev = G[from].size() - 1, ee.cost = -cost;
G[to].push_back(ee);
}
int min_cost_flow(int s, int t, int f) {
int res = 0;
fill(h, h + V, 0);//初始化h
while (f > 0) {
//使用Dijkstra算法更新h
priority_queue<P, vector<P>, greater<P> >q; //greater需要<functional>头文件,注意> >中间要加" "
fill(dist, dist + V, inf);
dist[s] = 0;
q.push(P(0, s));
while (!q.empty()) {
P p = q.top(); q.pop();
int v = p.second;
if (dist[v] < p.first)continue;
for (int i = 0; i < G[v].size(); i++) {
edge &e = G[v][i];
if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
prevv[e.to] = v;
preve[e.to] = i;
q.push(P(dist[e.to], e.to));
}
}
}
if (dist[t] == inf)//不能再增广
return -1;
for (int v = 0; v < V; v++)
h[v] += dist[v];
//沿s->t的最短路尽量增广
int d = f;
for (int v = t; v != s; v = prevv[v])
d = min(d, G[prevv[v]][preve[v]].cap);
f -= d;
res += d*h[t];
for (int v = t; v != s; v = prevv[v]) {
edge &e = G[prevv[v]][preve[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}
int main() {
int m, u, v, w;
while (~scanf("%d%d", &V, &m)) {
while (m--) {
scanf("%d%d%d", &u, &v, &w);
u--, v--;
add(u, v, 1, w);
add(v, u, 1, w);
}
printf("%d\n", min_cost_flow(0, V - 1, 2));//这个是从0到v-1的
}
return 0;
}