WrongAnswer_90

一言(ヒトコト)

P10541 [THUPC2024] 研发计划

My Blogs

P10541 [THUPC2024] 研发计划

首先看上去就比较像流,直接考虑怎么建模。

如果没有 \(h\) 就是裸的最大权闭合子图:\(S\) 向每个技术连边,每个收益向 \(T\) 连边,然后技术指向收益的边连 inf,做最小割(割掉的表示支付的代价),答案就是收益之和减去最小割。

现在有了 \(h\),要做的大概形如:如果一堆技术全都割掉了和 \(S\) 的边,那某个技术代价可以更小。首先要割掉的是 \(h\) 或者 \(f\),所以两者应当是串联的。然后稍微尝试一下就能发现 \(h\) 应该连在前面:

image.png

上图表示 \(3,4\)\(1\) 的前置,然后 \(3\)\(5\) 的前置,\(2\)\(3\) 的前置。可以发现这样建模只有所有前置都被割掉才会割 \(h\),否则割的是 \(f\),然后跑 dinic 即可。

	int n,m,X,Y,S,T;
	int cnt=1,head[410],to[100010],nex[100010],v[100010],now[410],d[410];
	inline void Add(int x,int y,int z){to[++cnt]=y,v[cnt]=z,nex[cnt]=head[x],head[x]=cnt;}
	inline void add(int x,int y,int z){Add(x,y,z),Add(y,x,0);}
	queue<int> q;
	inline bool bfs()
	{
		while(!q.empty())q.pop();
		q.e(S),memset(d,0,sizeof(d)),d[S]=1,now[S]=head[S];
		while(!q.empty())
		{
			int nw=q.front();q.pop();
			for(int i=head[nw];i;i=nex[i])
			{
				if(!d[to[i]]&&v[i])
				{
					d[to[i]]=d[nw]+1,now[to[i]]=head[to[i]],q.e(to[i]);
					if(to[i]==T)return 1;
				}
			}
		}
		return 0;
	}
	int dinic(int x,int flow)
	{
		if(x==T)return flow;
		int rest=flow,t;
		for(int i=head[x];i&&rest;i=nex[i])
		{
			now[x]=i;
			if(!v[i]||d[to[i]]!=d[x]+1)continue;
			t=dinic(to[i],min(rest,v[i]));
			if(!t)d[to[i]]=0;
			v[i]-=t,v[i^1]+=t,rest-=t;
		}
		return flow-rest;
	}
	inline void mian()
	{
		read(n,m,X,Y),S=3*n+m+1,T=S+1;int x,y,ans=0;
		for(int i=1;i<=n;++i)read(x),add(S,i,INF),add(i+n,i+n*2,x);
		for(int i=1;i<=n;++i)read(x),add(i,i+n,x);
		for(int i=1;i<=m;++i)read(x),add(3*n+i,T,x),ans+=x;
		while(X--)read(x,y),add(x+n*2,y+n*3,INF);
		while(Y--)read(x,y),add(x+n*2,y+n,INF);
		while(bfs())while((x=dinic(S,INF)))ans-=x;
		write(ans);
	}
posted @ 2024-05-31 16:07  WrongAnswer_90  阅读(11)  评论(0编辑  收藏  举报