luogu P4043 [AHOI2014/JSOI2014]支线剧情
题面传送门
这个其实是板子题。
容易发现我们需要让每条边的下界是\(1\),上界是正无穷。
所以模仿最大流一样的建边跑最小费用最大流然后再加上每条边本来的费用即可。
时间复杂度\(O(能过)\)
code:
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db long double
#define N 300
#define eps (1e-14)
#define mod 998244353
#define U unsigned
using namespace std;
int n,m,x,y,d[N+5],pre[N+5],g[N+5],ans,now,S,T,st,t,in[N+5];
struct yyy{int to,w,g,z;}tmp;
struct ljb{
int head,h[N+5];yyy f[N+5<<6];
I void add(int x,int y,int z,int g){f[head]=(yyy){y,z,g,h[x]};h[x]=head++;}
}s;queue<int> q;
I void MakeE(int x,int y,int w,int g){s.add(x,y,w,g);s.add(y,x,-w,0);}
I int bfs(){
memset(d,0x3f,sizeof(d));d[S]=0;q.push(S);g[S]=1e9;while(!q.empty()){
now=q.front();q.pop();for(int i=s.h[now];~i;i=tmp.z){
tmp=s.f[i];if(d[tmp.to]<=d[now]+tmp.w||!tmp.g) continue;
d[tmp.to]=d[now]+tmp.w;g[tmp.to]=min(g[now],tmp.g);pre[tmp.to]=i;q.push(tmp.to);
}
}
return d[T]<1e9;
}
int main(){
freopen("1.in","r",stdin);
re int i;scanf("%d",&n);st=1;t=n+1;T=n+2;memset(s.h,-1,sizeof(s.h));for(i=1;i<=n;i++){
scanf("%d",&m);while(m--) scanf("%d%d",&x,&y),ans+=y,in[i]--,in[x]++,MakeE(i,x,y,1e9);
}
for(i=2;i<=n+1;i++)MakeE(i,t,0,1e9);MakeE(t,st,0,1e9);for(i=1;i<=n;i++) in[i]>0?MakeE(S,i,0,in[i]):MakeE(i,T,0,-in[i]);
while(bfs()){
ans+=d[T]*g[T];now=T;while(now^S) s.f[pre[now]].g-=g[T],s.f[pre[now]^1].g+=g[T],now=s.f[pre[now]^1].to;
}
printf("%d\n",ans);
}