BZOJ 1927: [Sdoi2010]星际竞速 [最小费用最大流]
来源:互联网 发布:淘宝网音乐芯片 编辑:程序博客网 时间:2024/05/16 09:24
题面传送门
题解
类似DAG上的最小路径覆盖
最小费用流,建图 令源点为
S向所有入点连容量为1,费用为0的边
S向所有出点连容量为1,费用为
所有出点与T连容量为1,费用为0的边
对于有边的
理解一下:相当于如果要到
#include<cstdio>#include<algorithm>#include<cstring>#include<queue>#define N 2*805#define M 15005using namespace std;struct edge{int to,nxt,v,c;}e[M<<3];int n,m,cnt,s,t,head[N],dis[N],from[N],pre[N];bool v[N];inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline int read(){ int a=0;char f=1,c=nc(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();} while(c>='0'&&c<='9'){a=a*10+c-'0';c=nc();} return a*f;}inline void add(int x,int y,int v,int c){ e[++cnt]=(edge){y,head[x],v,c}; head[x]=cnt; e[++cnt]=(edge){x,head[y],0,-c}; head[y]=cnt;}bool spfa(){ queue<int>q; memset(dis,0x3f3f3f3f,sizeof(dis)); memset(from,-1,sizeof(from)); q.push(s); v[0]=1;dis[s]=0; while(!q.empty()){ int u=q.front(); q.pop(),v[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt) if(e[i].v&&dis[u]+e[i].c<dis[e[i].to]){ dis[e[i].to]=dis[u]+e[i].c; from[e[i].to]=u,pre[e[i].to]=i; if(!v[e[i].to]) q.push(e[i].to),v[e[i].to]=1; } } return from[t]!=-1;}int main(){ memset(head,-1,sizeof(head)); n=read(),m=read(); s=0,t=(n<<1)+1; cnt=-1; for(int i=1,x;i<=n;++i){ x=read(); add(s,n+i,1,x); add(s,i,1,0); add(n+i,t,1,0); } for(int i=1,x,y,z;i<=m;++i){ x=read(),y=read(),z=read(); if(x>y) swap(x,y); add(x,n+y,1,z); } int cost=0; while(spfa()){ int f=5; for(int i=t;i!=s;i=from[i]) f=min(f,e[pre[i]].v); for(int i=t;i!=s;i=from[i]){ e[pre[i]].v-=f; e[pre[i]^1].v+=f; } cost+=f*dis[t]; } printf("%d\n",cost); return 0;}
阅读全文