BZOJ 2427 [HAOI2010]软件安装

题解:

在一个环内的软件要么都安要么都不安

先缩点,然后这是一棵树

树形背包即可

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2009;

int n,m;
int inw[maxn],inv[maxn],b[maxn];

int cntedge=0;
int head[maxn]={0};
int to[maxn<<1],nex[maxn<<1];
void Addedge(int x,int y){
	nex[++cntedge]=head[x];
	to[cntedge]=y;
	head[x]=cntedge;
}


int dfsclock,scccnt;
int sccno[maxn],pre[maxn],lowlink[maxn];
int Sta[maxn],top=0;
void Dfs(int u){
	pre[u]=lowlink[u]=++dfsclock;
	Sta[++top]=u;
	
	int v=b[u];
	if(!v){
	}else if(!pre[v]){
		Dfs(v);
		lowlink[u]=min(lowlink[u],lowlink[v]);
	}else if(!sccno[v]){
		lowlink[u]=min(lowlink[u],pre[v]);
	}
	
	if(lowlink[u]==pre[u]){
		++scccnt;
		for(;;){
			int x=Sta[top--];
			sccno[x]=scccnt;
			if(x==u)break;
		}
	}
}

int w[maxn]={0},v[maxn]={0};
int father[maxn]={0};
void Tarjan(){
	for(int i=1;i<=n;++i)if(!pre[i])Dfs(i);
	
	for(int i=1;i<=n;++i){
		w[sccno[i]]+=inw[i];
		v[sccno[i]]+=inv[i];
		if(!b[i])continue;
		if(sccno[i]!=sccno[b[i]]){
			Addedge(sccno[b[i]],sccno[i]);
			father[sccno[i]]=sccno[b[i]];
		}
	}
}

int f[maxn][maxn];
void Dp(int x){
	for(int i=head[x];i;i=nex[i]){
		int v=to[i];
		Dp(v);
		for(int j=m;j>=0;--j){
			for(int k=0;k<=j;++k){
				f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]);
			}
		}
	}
	
	for(int i=m;i>=w[x];--i)f[x][i]=f[x][i-w[x]]+v[x];
	for(int i=0;i<w[x];++i)f[x][i]=0;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&inw[i]);
	for(int i=1;i<=n;++i)scanf("%d",&inv[i]);
	for(int i=1;i<=n;++i)scanf("%d",&b[i]);
	
	Tarjan();
	
	for(int i=1;i<=scccnt;++i)if(!father[i])Addedge(0,i);
	
	Dp(0);
//	for(int i=0;i<=n;++i){
//		for(int j=1;j<=m;++j){
//			cout<<f[i][j]<<' ';
//		}
//		cout<<endl;
//	}
	for(int i=1;i<=m;++i)f[0][i]=max(f[0][i],f[0][i-1]);
	cout<<f[0][m]<<endl;
	return 0;
}

  

自己还是太辣鸡了
原文地址:https://www.cnblogs.com/zzyer/p/8560697.html