1. 程式人生 > >BZOJ3876 AHOI/JSOI2014支線劇情(上下界網絡流)

BZOJ3876 AHOI/JSOI2014支線劇情(上下界網絡流)

就是 inf endif ring 網絡 con 利用 sin har

  原圖所有邊下界設為1上界設為inf花費為時間,那麽顯然就是一個上下界最小費用流了。做法與可行流類似。

  由於原圖是一個DAG,跑出來的可行流就是最小流,因為對於一般圖來說最小流小於可行流的原因就是其中有環而可以利用這一點達到退流。既然是最小流,每次增廣又保證了費用最小,且顯然不會有負權增廣路,所以跑可行流求出的就是最小費用了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using
namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 310 #define M 20010 #define inf 100000000 #define S 0 #define T 301 int n,p[N],t=-1
,pre[N],q[N],d[N],degree[N],ans=0; bool flag[N]; struct data{int to,nxt,cap,flow,cost; }edge[M]; void addedge(int x,int y,int z,int cost) { t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,edge[t].cost=cost,p[x]=t; t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,edge[t].cost=-cost,p[y]=t; }
int inc(int &x){x++;if (x>n+1) x-=n+1;return x;} bool spfa() { memset(d,42,sizeof(d));d[S]=0; memset(flag,0,sizeof(flag)); int head=0,tail=1;q[1]=S; do { int x=q[inc(head)];flag[x]=0; for (int i=p[x];~i;i=edge[i].nxt) if (d[x]+edge[i].cost<d[edge[i].to]&&edge[i].flow<edge[i].cap) { d[edge[i].to]=d[x]+edge[i].cost; pre[edge[i].to]=i; if (!flag[edge[i].to]) { q[inc(tail)]=edge[i].to; flag[edge[i].to]=1; } } }while (head!=tail); return d[T]<inf; } void ekspfa() { while (spfa()) { int v=inf; for (int i=T;i!=S;i=edge[pre[i]^1].to) v=min(v,edge[pre[i]].cap-edge[pre[i]].flow); for (int i=T;i!=S;i=edge[pre[i]^1].to) ans+=v*edge[pre[i]].cost,edge[pre[i]].flow+=v,edge[pre[i]^1].flow-=v; } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3876.in","r",stdin); freopen("bzoj3876.out","w",stdout); const char LL[]="%I64d"; #else const char LL[]="%lld"; #endif n=read(); memset(p,255,sizeof(p)); for (int i=1;i<=n;i++) { int k=read(); if (i>1) addedge(i,1,inf,0); while (k--) { int x=read(),y=read(); addedge(i,x,inf,y); degree[i]++;degree[x]--; ans+=y; } } for (int i=1;i<=n;i++) if (degree[i]>0) addedge(i,T,degree[i],0); else if (degree[i]<0) addedge(S,i,-degree[i],0); ekspfa(); cout<<ans; return 0; }

BZOJ3876 AHOI/JSOI2014支線劇情(上下界網絡流)