项目发展规划 题解

考虑怎么样构成一张等价的图。
对于一个点,如果这个点有必须点,就在这个点和必须点之间连一条流量为\(\infty\)的边,这样就保证了选择这个点的同时必然会选择这个点的必须点。
然后考虑那些价值为正的点,我们让源点和它连一条流量为该点价值的边,然后考虑价值为负的,让这个点和汇点流一条流量为这个价值的绝对值的边。
那么最终的答案就是净利润减去上面图的最小割。

#include<bits/stdc++.h>
#define int long long
int n,ans;
int ans_list[1000000],A_cnt;
int S=1,T=2;
int value[1000000];
int deep[1000000];
int head[60000],cur[60000],tot=1;
std::queue<int>q;
struct Edge{
	int to,nxt,flow;
}e[1000000];
void add(int from,int to,int flow){
	e[++tot]={to,head[from],flow};
	head[from]=tot;
	e[++tot]={from,head[to],0};
	head[to]=tot;
}
bool bfs(){
	while(!q.empty())
	  q.pop();
	memset(deep,-1,sizeof deep);
	deep[S]=0;
	for(int i=0;i<=tot;++i)
		cur[i]=head[i];
	q.push(S);
	while(!q.empty()){
		int X=q.front();
		q.pop();
		for(int i=head[X],y;i;i=e[i].nxt){
		  y=e[i].to;
		  if(deep[y]<0&&e[i].flow){
		  	deep[y]=deep[X]+1;
		  	q.push(y);
		  	if(y==T)
				  return 1;
		  }
		}
	}
	return 0;
}
int dfs(int x,int flow){
	if(x==T||!flow)
	  return flow;
	int Flow=0;
	for(int &i=cur[x],y;i;i=e[i].nxt){
		y=e[i].to;
		if(e[i].flow&&deep[y]==deep[x]+1){
			if(int w=dfs(y,std::min(flow,e[i].flow))){
				e[i].flow-=w;
				e[i^1].flow+=w;
				Flow+=w;
				flow-=w;
				if(!flow)break;
			}
		}
	}
	if(!flow)
	  deep[x]=-1;
	return Flow;
}
void dinic(){
	while(bfs())
		ans-=dfs(S,1e15);
}
main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;++i){
	  scanf("%lld",&value[i]);
	  if(value[i]>0){
	  	ans+=value[i];
	    add(S,i+2,value[i]);
	  }
	  if(value[i]<0)
	    add(i+2,T,-value[i]);
	  int pre_cnt;
	  scanf("%lld",&pre_cnt);
	  for(int j=1;j<=pre_cnt;++j){
	  	int pre;
	  	scanf("%lld",&pre);
	  	add(i+2,pre+2,1e9);
	  }
	}
	dinic();
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-05-31 09:25  SsssssskyLight  阅读(122)  评论(1编辑  收藏  举报