最短路对应费用,路径数量对应流量。为限制点经过次数,拆点为边。跑一次流量为2的最小费用最大流。
最小费用最大流和最大流EK算法是十分相似的,只是把找增广路的部分换成了求费用的最短路。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxv = 2000+5; const int maxe = 22000+5; struct Edge { int v,cap,cost,nxt; void IN(int V,int C,int c,int N) { v = V; cap = C; cost = c; nxt = N; } }edges[maxe]; int head[maxv],ecnt,vcnt; void AddEdge(int u,int v,int C,int c) { edges[ecnt].IN(v,C,c,head[u]); head[u] = ecnt++; edges[ecnt].IN(u,0,-c,head[v]); head[v] = ecnt++; } const int INF = 0x3f3f3f3f; int S,T; bool vis[maxv]; int d[maxv],p[maxv],a[maxv]; bool spfa() { memset(d,0x3f,sizeof(int)*vcnt); memset(vis,0,sizeof(bool)*vcnt); queue<int> q; q.push(S); d[S] = 0; a[S] = INF; while(q.size()){ int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; ~i; i = edges[i].nxt){ Edge &e = edges[i]; if(e.cap&& d[e.v] > d[u]+e.cost){ d[e.v] = d[u] + e.cost; p[e.v] = i; a[e.v] = min(a[u],e.cap); if(!vis[e.v]) { q.push(e.v); vis[e.v] = true; } } } } return d[T] != INF; } ll MinCostMaxFlow() { ll cost = 0; while(spfa()){ cost += d[T]; for(int i = T; i != S; i = edges[p[i]^1].v){ edges[p[i]].cap -= a[T]; edges[p[i]^1].cap += a[T]; } } return cost; } int pin[maxv],pout[maxv]; int main() { //freopen("in.txt","r",stdin); int v,e; int S = 0; T = 1; while(~scanf("%d%d",&v,&e)){ vcnt = 2; ecnt = 0; pin[1] = pout[1] = vcnt++; pin[v] = pout[v] = vcnt++; for(int i = 2; i < v; i++) { pin[i] = vcnt++; pout[i] = vcnt++; } memset(head,-1,sizeof(int)*(vcnt)); AddEdge(S,pin[1],2,0); AddEdge(pout[v],T,2,0); for(int i = 2; i < v; i++) AddEdge(pin[i],pout[i],1,0); while(e--){ int u,v,c; scanf("%d%d%d",&u,&v,&c); AddEdge(pout[u],pin[v],1,c); } printf("%lld ",MinCostMaxFlow()); } return 0; }