版权声明:~~~感谢支持! https://blog.csdn.net/qq_39897867/article/details/88314498
题目
http://www.joyoi.cn/problem/tyvj-1452
解题思路
对于一个图,如果上面有环,显然选不了,可以先用拓扑排序找环。
然后考虑最大子权闭合图(我也不太懂),对于正数点用原点连接,而负数点则连接汇点——容量为权值的绝对值。
跑一遍dinic即可。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,x,y) for (register int i=x;i<=y;i++)
using namespace std;
const int N=510,inf=2147483647/3;
struct node{int to,next,w;}a[N*N*2];
int n,cnt,head[N],in[N],v[N],ans,dep[N],s,t,m[N],edge[N][N];
queue<int>q;
void addq(int x,int y){
a[++cnt]=(node){y,head[x],0},head[x]=cnt,in[y]++;
}
void addw(int x,int y,int w){
a[++cnt]=(node){y,head[x],w};head[x]=cnt;
a[++cnt]=(node){x,head[y],0};head[y]=cnt;
}
void tops()
{
rep(i,1,n) if(!in[i]) q.push(i);
while(!q.empty()){
int x=q.front(); q.pop();
for(register int i=head[x];i;i=a[i].next){
int y=a[i].to;
in[y]--;
if(!in[y]) q.push(y);
}
}
}
bool bfs()
{
memset(dep,0,sizeof(dep));
while(!q.empty()) q.pop();
q.push(s);dep[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(register int i=head[x];i;i=a[i].next){
int y=a[i].to;
if(!dep[y]&&a[i].w){
dep[y]=dep[x]+1;
if(y==t) return 1;
q.push(y);
}
}
}
return 0;
}
int dinic(int x,int flow)
{
int rest=0,k;
if(x==t) return flow;
for(register int i=head[x];i;i=a[i].next){
int y=a[i].to;
if(dep[x]+1==dep[y]&&a[i].w){
rest+=(k=dinic(y,min(a[i].w,flow-rest)));
a[i].w-=k;a[i^1].w+=k;
if(rest==flow) return flow;
}
}
if (!rest) dep[x]=0;
return rest;
}
int main()
{
scanf("%d",&n);
rep(i,1,n){
scanf("%d%d",&v[i],&m[i]);
rep(j,1,m[i])
scanf("%d",&edge[i][j]),addq(edge[i][j],i);
}
tops();
cnt=1;s=n+1;t=n+2;
memset(head,0,sizeof(head));
rep(i,1,n){
if(in[i]) continue;
if(v[i]<0) addw(i,t,-v[i]); else addw(s,i,v[i]),ans+=v[i];
rep(j,1,m[i]){
if(in[edge[i][j]]) continue;
addw(i,edge[i][j],inf);
}
}
while(bfs()) ans-=dinic(s,inf);
printf("%d",ans);
}