bzoj1927: [Sdoi2010]星际竞速

来源:互联网 发布:多通道数据采集系统 编辑:程序博客网 时间:2024/04/29 16:41

费用流建图。

因为从小往大连边,所以不会出现环。

因为所有点都要经过,所以可以考虑它从那个点拓展而来。拆点,从源点向出点连容量1,费用为定位时间的边,向入点连容量为1,费用为0的边,从出边向汇点连容量为1,费用为0的边,对于x-->y,从x的入点向y的出点连容量为1,费用为时间的边。这样可以保证最大流的每个点都使用且最多拓展出一个点。

然后最小费用流(窝太弱,只会SPFA。。

#include<iostream>#include<cstdio>#include<cstring>#define N 2000#define M 40010#define inf 100000000using namespace std;int n,m,l=1,first[N],next[M],to[M],v[M],c[M],cnt,x,y,z,q[N*2],dis[N],fa[N],Ans,fl[N];bool flag[N];void link(int x,int y,int V,int C){to[++l]=y;v[l]=V;c[l]=C; next[l]=first[x];first[x]=l;to[++l]=x;v[l]=0;c[l]=-C;next[l]=first[y];first[y]=l;}bool SPFA(){int head=0,tail=1;memset(fl,0x3f,sizeof fl);memset(flag,0,sizeof flag);memset(dis,0x3f,sizeof dis);q[1]=0;fl[0]=inf;dis[0]=0;while (head!=tail){head++;if (head==N) head=0;x=q[head];flag[x]=0;for (int i=first[x];i;i=next[i]){if (dis[to[i]]>dis[x]+c[i]&&v[i]>0){dis[to[i]]=dis[x]+c[i];fa[to[i]]=i;fl[to[i]]=min(fl[x],v[i]);if (!flag[to[i]]){flag[to[i]]=1;tail++;if (tail==N) tail=0;q[tail]=to[i];}}}}return fl[cnt]<inf;}void flow(){for (int i=cnt;i;i=to[fa[i]^1]){v[fa[i]]-=fl[cnt];v[fa[i]^1]+=fl[cnt];Ans+=c[fa[i]]*fl[cnt];}}int main(){scanf("%d%d",&n,&m);cnt=n+n+1;for (int i=1;i<=n;i++)scanf("%d",&x),link(0,i+n,1,x);for (int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&z);if (x>y) swap(x,y);link(x,y+n,1,z);}for (int i=1;i<=n;i++)link(0,i,1,0),link(i+n,cnt,1,0);while(SPFA()) flow();printf("%d\n",Ans);}

0 0