您的位置:首页 > 其它

bzoj 1877: [SDOI2009]晨跑 费用流

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

分析:

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

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

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

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define inf 0x7fffffff
using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: