项目发展规划 题解
考虑怎么样构成一张等价的图。
对于一个点,如果这个点有必须点,就在这个点和必须点之间连一条流量为\(\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;
}