把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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);
}
posted @ 2021-06-05 22:42  275307894a  阅读(33)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end