这个题的意思是农夫约翰要呆人参观他的农场, 刚开始从1开始走, 走到N后又返回1点, 两次不能走相同的路, 问农夫约翰走的最短的路是多少??
我们可以用最小MCMF来解决这个问题, 对于图中的每一条边, 我们建立了两条流量为1, 费用为边权的边, 再增加一个源点和一个汇点, 源点指向1, 流量为2,费用为0, N指向汇点, 流量为2费用为0, 然后求出最小费用即可, 代码如下:
#include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <vector> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1000+10; int n; //n个顶点 struct Edge{ int from, to, cap, flow, cost; }; vector<Edge> edges; vector<int> G[maxn]; int inque[maxn]; //SPFA 需要用到 int d[maxn]; //当前点到源点的最短路 int p[maxn]; //连接当前点的弧 int a[maxn]; //可改进量 void init() { for(int i=0; i<=n; i++) G[i].clear(); edges.clear(); } void add_edge(int from, int to, int cap, int cost) { edges.push_back((Edge){from, to, cap, 0, cost}); edges.push_back((Edge){to, from, 0, 0, -cost}); int m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool spfa(int s, int t, int &flow, long long &cost) { for(int i=0; i<=n; i++) d[i] = inf; memset(inque, 0, sizeof(inque)); d[s] = 0; inque[s]=1; p[s] = 0; a[s] = inf; queue<int> que; que.push(s); while(!que.empty()){ int u = que.front(); que.pop(); inque[u] = 0; for(int i=0; i<G[u].size(); i++){ Edge e = edges[G[u][i]]; if(e.cap>e.flow && d[e.to]>d[u]+e.cost){ d[e.to] = d[u] + e.cost; if(!inque[e.to]) que.push(e.to), inque[e.to]=1; p[e.to] = G[u][i]; //e.to连接的边是G[u][i] a[e.to] = min(a[u], e.cap-e.flow); //更新可改进量 } } } if(d[t] == inf) return false; flow += a[t]; cost += (long long)a[t] * (long long)d[t]; for(int u=t; u!=s; u=edges[p[u]].from) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; } return true; } int MCMF(int s, int t, long long &cost) { int flow = 0; cost = 0; while(spfa(s, t, flow, cost)); return flow; } int N, M; int main() { scanf("%d%d", &N, &M); n = N+2; init(); for(int i=0; i<M; i++) { int u, v, c; scanf("%d%d%d", &u, &v, &c); add_edge(u, v, 1, c); add_edge(v, u, 1, c); } add_edge(0, 1, 2, 0); add_edge(N, N+1, 2, 0); long long cost; MCMF(0, N+1, cost); printf("%lld\n", cost); return 0; }
时间: 2024-11-05 16:05:26