bzoj 1877: [SDOI2009]晨跑 费用流

来源:互联网 发布:修真淘宝大户无弹 编辑:程序博客网 时间:2024/06/05 17:33

题意:给出一个有向图,求从起点到终点最多能找到多少条不相交的路径和这些路径的最小总长度。


分析:

如果只有第一问的话就是拆点最大流

第二问就是裸的拆点费用流


费用流的原理就是每次找最小费用可增广路来进行增广(用spfa来实现)


代码:

#include<iostream>#include<cstdio>#include<cstdlib>#define inf 0x7fffffffusing namespace std;int n,m,cnt=0,last[1001]={0},s,t,dis[1001],v[1001],q[1001],ans1=0,ans2=0,pre[1001];struct data{int x,y,c,w,next,op;}e[100001];void insert(int x,int y,int w,int c){cnt++;e[cnt].x=x;e[cnt].y=y;e[cnt].w=w;e[cnt].c=c;e[cnt].op=cnt+1;e[cnt].next=last[x];last[x]=cnt;cnt++;e[cnt].x=y;e[cnt].y=x;e[cnt].w=0;e[cnt].c=-c;e[cnt].op=cnt-1;e[cnt].next=last[y];last[y]=cnt;}bool spfa(){for (int i=s;i<=t;i++){dis[i]=inf;v[i]=0;}int head=0,tail=1;q[1]=s;v[s]=1;dis[s]=0;while(head!=tail){if (head==1000)head=0;head++;int now=q[head],i=last[now];while (i){if (e[i].w&&dis[now]+e[i].c<dis[e[i].y]){dis[e[i].y]=dis[now]+e[i].c;pre[e[i].y]=i;if (!v[e[i].y]){v[e[i].y]=1;if (tail==1000)tail=0;tail++;q[tail]=e[i].y;}}i=e[i].next;}v[now]=0;}if (dis[t]==inf) return 0;return 1;}void mcf(){int x=inf,i=t;while (pre[i]){x=min(e[pre[i]].w,x);i=e[pre[i]].x;}ans1++;i=t;while (i){e[pre[i]].w-=x;e[e[pre[i]].op].w+=x;ans2+=e[pre[i]].c*x;i=e[pre[i]].x;}}int main(){scanf("%d%d",&n,&m);s=1;t=n+n;for (int i=0;i<m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);insert(u+n,v,1,w);}for (int i=2;i<n;i++)insert(i,i+n,1,0);insert(s,s+n,inf,0);insert(n,t,inf,0);while(spfa())mcf();printf("%d %d\n",ans1,ans2);return 0;}


0 0
原创粉丝点击