Description
Input
Output
题目大意:给一个n个点m条边的无向图,求从1走到n再从n走到1的最短路径,要求边不重复。
思路:建立一个附加源点S,连一条边到点1,容量为2,费用为0;建立一个附加汇点T,从n连一条边到T,容量为2,费用为0;对于每条边u、v,连一条边u到v,容量为1,费用为距离,再连一条边v到u,容量为1,费用为距离。最小费用最大流为答案。
建图正确性略微说明:可以考虑两次从1走到n,边不重复,那么建图流两个流量从源点到汇点,最小的费用就保证了距离最短。由于边长度为非负数,那么最小花费一定不会是一条路径从u到v,另一条路径从v到u,如果这样走了两次,还不如两条路径都不经过u-v,都走另外一条路的后继路径(不要跟我说长度是0怎么破)
PS:忘了改数组大小又TLE了一次T_T,怎么老是忘
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int MAXV = 1010; 9 const int MAXE = 40010; 10 const int INF = 0x7f7f7f7f; 11 12 struct SPFA_COST_FLOW { 13 bool vis[MAXV]; 14 int head[MAXV], dis[MAXV], pre[MAXV]; 15 int to[MAXE], next[MAXE], cost[MAXE], flow[MAXE]; 16 int n, st, ed, ecnt; 17 18 void init() { 19 memset(head, 0, sizeof(head)); 20 ecnt = 2; 21 } 22 23 void add_edge(int u, int v, int c, int w) { 24 to[ecnt] = v; flow[ecnt] = c; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++; 25 to[ecnt] = u; flow[ecnt] = 0; cost[ecnt] = -w; next[ecnt] = head[v]; head[v] = ecnt++; 26 } 27 28 bool spfa() { 29 memset(vis, 0, sizeof(vis)); 30 memset(dis, 0x7f, sizeof(dis)); 31 queue<int> que; que.push(st); 32 vis[st] = true; dis[st] = 0; 33 while(!que.empty()) { 34 int u = que.front(); que.pop(); 35 vis[u] = false; 36 for(int p = head[u]; p; p = next[p]) { 37 int &v = to[p]; 38 if(flow[p] && dis[v] > dis[u] + cost[p]) { 39 dis[v] = dis[u] + cost[p]; 40 pre[v] = p; 41 if(!vis[v]) { 42 vis[v] = true; 43 que.push(v); 44 } 45 } 46 } 47 } 48 return dis[ed] < INF; 49 } 50 51 int maxFlow, minCost; 52 53 int min_cost_flow(int ss, int tt, int nn) { 54 st = ss, ed = tt, n = nn; 55 maxFlow = minCost = 0; 56 while(spfa()) { 57 minCost += dis[ed]; 58 int u = ed, tmp = INF; 59 while(u != st) { 60 tmp = min(tmp, flow[pre[u]]); 61 u = to[pre[u] ^ 1]; 62 } 63 u = ed; 64 while(u != st) { 65 flow[pre[u]] -= tmp; 66 flow[pre[u] ^ 1] += tmp; 67 u = to[pre[u] ^ 1]; 68 } 69 maxFlow += tmp; 70 } 71 return minCost; 72 } 73 } G; 74 75 int n, m; 76 77 int main() { 78 scanf("%d%d", &n, &m); 79 G.init(); 80 int ss = n + 1, tt = n + 2; 81 while(m--) { 82 int u, v, c; 83 scanf("%d%d%d", &u, &v, &c); 84 G.add_edge(u, v, 1, c); 85 G.add_edge(v, u, 1, c); 86 } 87 G.add_edge(ss, 1, 2, 0); 88 G.add_edge(n, tt, 2, 0); 89 printf("%d\n", G.min_cost_flow(ss, tt, tt)); 90 }