uva 1658(最小费用流+拆点)
求最权值的两条不同路径,不能经过同一个点。直接用最小费用流写的话是不能经过同一条边,所以在这里用拆点法,设每个点a都存在一个与它容量为1的点a',由于最小费用流路径不能重复,所以点也就不在重复。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <vector> #include <queue> using namespace std; const int maxn=3000+100; const int maxm=10000+100; const int inf=0x3f3f3f3f; typedef long long ll; struct edge { int fr,to,c,f,cost; edge(int a,int b,int cc,int ff,int d):fr(a),to(b),c(cc),f(ff),cost(d) {} }; struct MCMF { int n; int m; int p[maxn],d[maxn],a[maxn]; int inq[maxn]; vector<edge> ee; vector<int> g[maxn]; void init(int n) { this->n=n; for(int i=0;i<=n;i++) g[i].clear(); ee.clear(); } void addage(int fr,int to,int c,int cost) { ee.push_back(edge(fr,to,c,0,cost)); ee.push_back(edge(to,fr,0,0,-cost)); m=ee.size(); g[fr].push_back(m-2); g[to].push_back(m-1); } bool spfa(int s,int t,int &flow,ll &cost) { // memset(a,0,sizeof(a)); memset(inq,0,sizeof(inq)); memset(d,inf,sizeof(d)); d[s]=0; p[s]=0; inq[s]=1; a[s]=inf; queue<int> q; q.push(s); while(q.size()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=0;i<g[u].size();i++) { edge &nn=ee[g[u][i]]; if((nn.c>nn.f)&&(d[nn.to]>d[nn.fr]+nn.cost)) { d[nn.to]=d[nn.fr]+nn.cost; a[nn.to]=min(nn.c-nn.f,a[nn.fr]); p[nn.to]=g[u][i]; if(!inq[nn.to]) { q.push(nn.to); inq[nn.to]=1; } } } } if(d[t]==inf) return 0; flow+=a[t]; cost+=(ll)d[t]*(ll)a[t]; for(int i=t;i!=s;i=ee[p[i]].fr) { ee[p[i]].f+=a[t]; ee[p[i]^1].f-=a[t]; } return 1; } int mincostmaxflow(int s,int t,ll &cost) { int flow=0; cost=0; while(spfa(s,t,flow,cost)); return flow; } }zzz; int n,m; int main() { while(~scanf("%d%d",&n,&m)) { zzz.init(n+n); for(int i=2;i<=n-1;i++) zzz.addage(i,n+i,1,0); zzz.addage(1,n+1,2,0); zzz.addage(n,n+n,2,0); int a,b,z; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&z); zzz.addage(n+a,b,1,z); } ll cost=0; zzz.mincostmaxflow(1,n+n,cost); printf("%lld\n",cost); } return 0; }
浙公网安备 33010602011771号