[HAOI2010]软件安装[缩点 树形dp]

[BZOJ2427] [luoguP2515]

每个人都至多有一个依赖点 所以有可能成环 先tarjan缩点并处理出环的信息wei va

再将缩点后的图重新连接 将入度为0的点和0点连接 这样就构成了一颗树

由此做树形dp 只有父亲节点选了它的儿子才能选 所以在访问进去时先把wei[u]~m都赋为va[u] 我会说我又因为树形dp卡了半天吗

#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
const int N=100+5,M=500+5,inf=0x3f3f3f3f,P=19650827;
int n,m,in[N],w[N],val[N],f[N][M];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int head[N],tot=0;
struct edge{int u,v,nxt;}e[N],E[N];
void add(int u,int v){
	e[++tot]=(edge){u,v,head[u]},head[u]=tot;
}
int idx=0,Bcnt=0,dfn[N],bl[N],low[N],wei[N],va[N];
stack<int>s;bool inst[N];
void tarjan(int u){
	dfn[u]=low[u]=++idx;
	s.push(u),inst[u]=1;
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].v;
		if(!dfn[v]) tarjan(v),low[u]=Min(low[u],low[v]);
		else if(inst[v]&&dfn[v]<low[u]) low[u]=dfn[v];
	}
	if(low[u]==dfn[u]){
		int v;++Bcnt;
		do{
			v=s.top(),s.pop();
			inst[v]=0,bl[v]=Bcnt,wei[Bcnt]+=w[v],va[Bcnt]+=val[v];
		}while(u!=v);
	}
}

int hd[N],tt=0;
void Add(int u,int v){
	E[++tt]=(edge){u,v,hd[u]},hd[u]=tt;
}
void dfs(int u){
	for(int i=wei[u];i<=m;++i) f[u][i]=va[u];
	for(int i=hd[u],v;i;i=E[i].nxt){
		v=E[i].v,dfs(v);
		for(int j=m-wei[u];j>0;--j)
		for(int k=0;k<=j;++k)
		f[u][j+wei[u]]=Max(f[u][j+wei[u]],f[u][j+wei[u]-k]+f[v][k]);
	}
}

int main(){
//	freopen("in2.txt","r",stdin);
	//freopen("xor.out","w",stdout);
	rd(n),rd(m); 
	for(int i=1;i<=n;++i) rd(w[i]);
	for(int i=1;i<=n;++i) rd(val[i]);
	for(int i=1,u;i<=n;++i){
		rd(u);
		if(u) add(u,i);
	}
	for(int i=1;i<=n;++i)
	if(!dfn[i]) tarjan(i);
	for(int i=1;i<=tot;++i)
	if(bl[e[i].u]!=bl[e[i].v]) Add(bl[e[i].u],bl[e[i].v]),++in[bl[e[i].v]];
	for(int i=1;i<=Bcnt;++i) if(!in[i]) Add(0,i);
	memset(f,0,sizeof(f));dfs(0);
	printf("%d",f[0][m]);
	return 0;
}
原文地址:https://www.cnblogs.com/lxyyyy/p/11390563.html