题意:给定一个无向图,要从1点到n点再返回1点,每条边最多走一次,问最短需要走多远。
分析:最小费用最大流,把题意看成是要找两条无交集的从1到n的路线,使距离和最小。图中的点和边就是网络流图中的点和边。设置一个源,接到1点,设置一个汇,从n点接到汇。为保证无交集,我们把每条边的流量设置为1,而源发出的流量和汇接收的流量均为2。每条边的费用就是该边在原图中的权值。
注意:有重边,所以要用邻接表。因为是无向图,所以要在加边时,原图中的一条边要变成网络流图中的两条边(如果把反向负权费用边也算上就总共4条边)。
由于最短路算法是最小费用最大流算法的子算法,所以有些最短路的题可能要用到最小费用最大流。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define typef int #define typec int #define maxn 1005 #define maxm 10005 #define N maxn + 2 #define E maxm * 4 + 4 const typef inff = 0x3f3f3f3f; const typec infc = 0x3f3f3f3f; struct network { int nv, ne, pnt[E], nxt[E]; int vis[N], que[N], head[N], pv[N], pe[N]; typef flow, cap[E]; typec cost, dis[E], d[N]; void addedge(int u, int v, typef c, typec w) { pnt[ne] = v; cap[ne] = c; dis[ne] = +w; nxt[ne] = head[u]; head[u] = (ne++); pnt[ne] = u; cap[ne] = 0; dis[ne] = -w; nxt[ne] = head[v]; head[v] = (ne++); } int mincost(int src, int sink) { int i, k, f, r; typef mxf; for (flow = 0, cost = 0;;) { memset(pv, -1, sizeof(pv)); memset(vis, 0, sizeof(vis)); for (i = 0; i < nv; ++i) d[i] = infc; d[src] = 0; pv[src] = src; vis[src] = 1; for (f = 0, r = 1, que[0] = src; r != f;) { i = que[f++]; vis[i] = 0; if (N == f) f = 0; for (k = head[i]; k != -1; k = nxt[k]) if (cap[k] && dis[k] + d[i] < d[pnt[k]]) { d[pnt[k]] = dis[k] + d[i]; if (0 == vis[pnt[k]]) { vis[pnt[k]] = 1; que[r++] = pnt[k]; if (N == r) r = 0; } pv[pnt[k]] = i; pe[pnt[k]] = k; } } if (-1 == pv[sink]) break; for (k = sink, mxf = inff; k != src; k = pv[k]) if (cap[pe[k]] < mxf) mxf = cap[pe[k]]; flow += mxf; cost += d[sink] * mxf; for (k = sink; k != src; k = pv[k]) { cap[pe[k]] -= mxf; cap[pe[k] ^ 1] += mxf; } } return cost; } void build(int v, int e) { nv = v; ne = 0; memset(head, -1, sizeof(head)); int x, y; typec w; for (int i = 0; i < e; ++i) { scanf("%d%d%d", &x, &y, &w); addedge(x, y, 1, w);// add arc (u->v, f, w) addedge(y, x, 1, w); } addedge(0, 1, 2, 0); addedge(v - 2, v - 1, 2, 0); } } g; int n, m; int main() { //freopen("t.txt", "r", stdin); scanf("%d%d", &n, &m); g.build(n + 2, m); printf("%d\n", g.mincost(0, n + 1)); return 0; }