1. 程式人生 > >BZOJ3876: [Ahoi2014&Jsoi2014]支線劇情(洛谷P4043)

BZOJ3876: [Ahoi2014&Jsoi2014]支線劇情(洛谷P4043)

最小費用可行流

和有源匯上下界可行流一樣建,除了加邊權外沒什麼區別。因為可以在任意節點結束,所以要對每個節點建一條到超級匯點的容量為++\infty邊權為0的邊。

程式碼:

#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 305
#define M 5005
#define F inline
using namespace std;
struct edge{ int nxt,to,v,d,
f; }ed[M<<3]; struct fat{ int x,e; }fa[N]; int n,k=1,s,t,ss,tt,ans,h[N],d[N],r[N],a[N]; bool f[N]; queue <int> q; F char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); return l==r?EOF:*l++; } F int _read(){ int x=0; char ch=readc(); while (!isdigit
(ch)) ch=readc(); while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc(); return x; } F void add(int x,int y,int z,int w){ if (x==0) x=0; ed[++k]=(edge){h[x],y,z,w},h[x]=k; ed[++k]=(edge){h[y],x,0,-w},h[y]=k; } F int spfa(){ for (int i=ss;i<=tt;i++) d[i]=1e9,f[i]=false; while (!
q.empty()) q.pop(); for (q.push(ss),d[ss]=0,r[ss]=1e9;!q.empty();){ int x=q.front(); q.pop(),f[x]=false; for (int i=h[x],v;i;i=ed[i].nxt) if (ed[i].v>ed[i].f&&d[x]+ed[i].d<d[v=ed[i].to]){ d[v]=d[x]+ed[i].d,fa[v].e=i,fa[v].x=x; r[v]=min(r[x],ed[i].v-ed[i].f); if (!f[v]) q.push(v),f[v]=true; } } return d[tt]==1e9?0:r[tt]; } int main(){ n=_read(),s=1,t=n+1,tt=n+2; for (int i=1,m;i<=n;i++){ m=_read(),a[i]-=m,add(i,t,1e9,0); for (int v,d;m;m--) v=_read(),d=_read(),a[v]++,ans+=d,add(i,v,1e9,d); } for (int i=1;i<=n;i++) if (a[i]>0) add(ss,i,a[i],0); else if (a[i]<0) add(i,tt,-a[i],0); add(t,s,1e9,0); for (int sum;sum=spfa();ans+=d[tt]*sum) for (int x=tt,e;x!=ss;x=fa[x].x) ed[e=fa[x].e].f+=sum,ed[e^1].f-=sum; return printf("%d\n",ans),0; }