版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88078410
一些有价值的点,选了某个点之前要选某个点,求最大价值
数据范围:边数和点数均小于500
首先环是不能选的(显然)
基环树或树的情况直接拓扑排序去环后树形 ,这样的复杂度显然是 的
但是我们通过观察数据范围,发现其实是允许 的做法过的,于是乎。。。
网络流大法好!
类似太空飞行计划问题,我们把选择某些点转换为放弃某些点,这就变成了一个最小割问题
正数左边,负数放右边
用 算法轻松解决
#include<queue>
#include<cstdio>
#include<vector>
#include<cctype>
#include<cstring>
#define N 511
#define M 250501
using namespace std;int n,rd[N],sum,s,t,v[N];
vector<int>g[N];
inline long long read()
{
char c;int d=1;long long f=0;
while(c=getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
char c;
bool flag;
struct node{int next,to,w;}e[M];
int l[N],tot,d[N];
bool vis[N];
void add(int u,int v,int w)
{
e[tot]=(node){l[u],v,w};l[u]=tot++;
e[tot]=(node){l[v],u,0};l[v]=tot++;
return;
}
bool bfs()
{
memset(d,-1,sizeof(d));
queue<int>q;d[s]=0;q.push(s);
while(q.size())
{
int x=q.front();q.pop();
for(int i=l[x];~i;i=e[i].next)
{
int y=e[i].to;
if(e[i].w&&d[y]==-1)
{
d[y]=d[x]+1;
if(y==t) return true;
q.push(y);
}
}
}
return false;
}
int dfs(int x,int flow)
{
if(x==t||!flow) return flow;
int rest=0,f=0;
for(int i=l[x];~i;i=e[i].next)
{
int y=e[i].to;
if(d[x]+1==d[y]&&e[i].w)
{
f=dfs(y,min(flow-rest,e[i].w));
if(!f) d[y]=-1;
e[i].w-=f;rest+=f;e[i^1].w+=f;
}
}
if(!rest) d[x]=-1;
return rest;
}
void dinic()
{
while(bfs()) sum-=dfs(s,1e9);
return;
}
inline void topsort()
{
queue<int>q;
int y,w;
for(register int i=1;i<=n;i++) if(!rd[i]) q.push(i);
while(q.size())
{
int x=q.front();q.pop();
for(register int i=0;i<g[x].size();i++) if(!--rd[y=g[x][i]]) q.push(y);
}
return;
}
signed main()
{
n=read();
for(register int i=1;i<=n;i++)
{
v[i]=read();rd[i]=read();
for(register int j=0;j<rd[i];j++) g[read()].push_back(i);
}
topsort();memset(l,-1,sizeof(l));s=n+1;t=n+2;
for(register int i=1;i<=n;i++)
{
if(rd[i]) continue;
if(v[i]<0) add(i,t,-v[i]);else add(s,i,v[i]),sum+=v[i];//先计算总和
for(register int j=0;j<g[i].size();j++)
{
int k=g[i][j];
if(rd[k]) continue;
add(k,i,1e9);
}
}
dinic();
printf("%d",sum);//再减
}