对于30%的数据,N ≤ 20,M ≤ 120。
对于100%的数据,N ≤ 200,M ≤ 20000。
费用流。
因为要求每个点最多经过一次,因此把每个十字路口拆点,连流量为1的边;
但是起点和终点可以经过无数次,因此起点和终点拆成的点连inf,并且从s到起点,终点到t分别连inf的边。
x,y有边相连,那么从x‘到y连流量为,费用为路径长度的边。
最后最大流就是路径条数,最小费用就是最短路径和。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <cstdlib> #define inf 0x3f3f3f3f #define M 400+5 #include <queue> using namespace std; queue<int> q; int tot=1,s=0,t,n,m,d[M],h[M],inq[M],a[M],p[M]; struct edge { int from,to,cap,flow,cost,ne; }E[200005]; void Addedge(int x,int y,int cap,int cost) { E[++tot]=(edge){x,y,cap,0,cost,h[x]}; h[x]=tot; E[++tot]=(edge){y,x,0,0,-cost,h[y]}; h[y]=tot; } bool spfa(int &flow,int &cost) { for (int i=s;i<=t;i++) d[i]=inf,inq[i]=0; q.push(s); inq[s]=1,d[s]=0,a[s]=inf,p[s]=0; while (!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; for (int i=h[x];i;i=E[i].ne) { edge e=E[i]; if (d[e.to]>d[x]+e.cost&&e.cap>e.flow) { d[e.to]=d[x]+e.cost; p[e.to]=i; a[e.to]=min(a[x],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]); int x=t; while (x!=s) { int y=p[x]; E[y].flow+=a[n]; E[y^1].flow-=a[n]; x=E[y].from; } return true; } void mincost() { int flow=0,cost=0; while (spfa(flow,cost)); printf("%d %d\n",flow,cost); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); Addedge(x+n,y,1,c); } for (int i=2;i<n;i++) Addedge(i,i+n,1,0); t=2*n+1; Addedge(1,n+1,inf,0),Addedge(n,n+n,inf,0); Addedge(s,1,inf,0),Addedge(2*n,t,inf,0); mincost(); return 0; }
原文地址:http://blog.csdn.net/regina8023/article/details/44341605