题目链接:https://uva.onlinejudge.org/external/16/1658.pdf
题意:求1到N的两条路(不能相交),距离和最小。
分析:
第一次做拆点,有点意思。刚开始一直出不了结果,原来是初始化少了一点。
注意的是:我想我的建图方法较刘汝佳的方法有一点小区别,加一个源点S,和汇点T,刘汝佳的方法是把2—v-1拆掉。
然后这里拆点有些技巧。还是阳哥教我的。
#include <iostream> #include <stdio.h> #include <cstring> #include <vector> #include <queue> #define INF 0x3f3f3f3f using namespace std; const int maxn = 2000 + 10; struct Edge { int from,to,cap,flow,cost; Edge() {} Edge(int a,int b,int c,int d,int e):from(a),to(b),cap(c),flow(d),cost(e) {} }; struct MCMF { int n,m,s,t; vector<Edge> edges; vector<int> g[maxn]; int inq[maxn]; int d[maxn]; int p[maxn]; int a[maxn]; void init(int n) { this->n =n; for(int i=0; i<n; i++)g[i].clear(); edges.clear(); } void addedge(int from,int to,int cap,int cost) { Edge e1= Edge(from,to,cap,0,cost), e2= Edge(to,from,0,0,-cost); edges.push_back(e1); edges.push_back(e2); m=edges.size(); g[from].push_back(m-2); g[to].push_back(m-1); } bool spfa(int s,int t, int & flow,int & cost) { for(int i=0; i<n; i++) d[i]=INF; memset(inq,0,sizeof(inq)); d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[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; p[e.to]=g[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]) { q.push(e.to); inq[e.to]=1; } } } } if(d[t]==INF) return false; flow+=a[t]; cost+=a[t]*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 MincostMaxflow(int s,int t) { int flow=0,cost =0; while(spfa(s,t,flow,cost)); return cost; } } sol; int main() { freopen("input.txt","r",stdin); int n, m; while(scanf("%d%d", &n, &m) == 2 && n) { int s = 0,t = 2*n+1; sol.init(t+1); for(int i=1;i<=n;i++) sol.addedge(i+n,i,1,0); sol.addedge(1,1+n,2,0); sol.addedge(n,2*n,2,0); for(int i=0;i<m;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); sol.addedge(u,v+n,1,c); } sol.addedge(0,1,2,0); sol.addedge(2*n,t,2,0); printf("%d ",sol.MincostMaxflow(0,t)); } return 0; }