[HAOI2010]软件安装

XVIII.[HAOI2010]软件安装

不知道大家有没有做过这道题[CTSC1997]选课啊,反正我一看到这道题,就想起了它——都是树上背包。所以我便高高兴兴的敲了一发背包交上去。

然后呢?光荣的WA掉了。

为什么呢?

因为这道题和选课不一样;选课是你没有修完前一节课就不能修这节;但是本题是你装软件是可以随便装,想咋装就咋装的——只不过会不会起效就不知道了。因此,如果成环的话,只要整个环全装上就行了。

那么我们就SCC缩个点,在缩出来的树上背包一下就行了(实际上数据还可以加强成DAG的……)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,w[110],v[110],f[110][510],g[510],res,col[110],val[110],sz[110],in[110],c;
namespace SCC{
	int tot,dfn[310],low[310],head[310],cnt;
	struct node{
		int to,next;
	}edge[200100];
	void ae(int u,int v){
	//	cout<<u<<" "<<v<<endl;
		edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
	}
	stack<int>stk;
	void Tarjan(int x){
		dfn[x]=low[x]=++tot,stk.push(x);
		for(int i=head[x];i!=-1;i=edge[i].next){
			if(!dfn[edge[i].to])Tarjan(edge[i].to),low[x]=min(low[x],low[edge[i].to]);
			if(!col[edge[i].to])low[x]=min(low[x],dfn[edge[i].to]);
		}
		if(low[x]<dfn[x])return;
		c++;
		while(stk.top()!=x)col[stk.top()]=c,val[c]+=v[stk.top()],sz[c]+=w[stk.top()],stk.pop();
		col[stk.top()]=c,val[c]+=v[stk.top()],sz[c]+=w[stk.top()],stk.pop();
	}
}
namespace DP{
	int head[110],cnt;
	struct node{
		int to,next;
	}edge[110];
	void ae(int u,int v){
//		printf("%d %d\n",u,v);
		edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
	}
	void dfs(int x){
		if(sz[x]<=m)f[x][sz[x]]=val[x];
		for(int i=head[x];i!=-1;i=edge[i].next){
			dfs(edge[i].to);
			for(int j=0;j<=m;j++)g[j]=f[x][j];
			for(int j=0;j<=m;j++)for(int k=0;j+k<=m;k++)if(f[x][j]!=-1&&f[edge[i].to][k]!=-1)g[j+k]=max(g[j+k],f[x][j]+f[edge[i].to][k]);
			for(int j=0;j<=m;j++)f[x][j]=g[j];
		}
	}	
}
int main(){
	scanf("%d%d",&n,&m),memset(f,-1,sizeof(f)),memset(SCC::head,-1,sizeof(SCC::head)),memset(DP::head,-1,sizeof(DP::head));
	for(int i=1;i<=n;i++)scanf("%d",&w[i]);
	for(int i=1;i<=n;i++)scanf("%d",&v[i]);
	for(int i=1,x;i<=n;i++){
		scanf("%d",&x);
		if(x)SCC::ae(x,i);
	}
	for(int i=1;i<=n;i++)if(!SCC::dfn[i])SCC::Tarjan(i);
//	for(int i=1;i<=c;i++)printf("%d %d\n",val[i],sz[i]);
	for(int i=1;i<=n;i++)for(int j=SCC::head[i];j!=-1;j=SCC::edge[j].next)if(col[i]!=col[SCC::edge[j].to])DP::ae(col[i],col[SCC::edge[j].to]),in[col[SCC::edge[j].to]]++;
	for(int i=1;i<=c;i++)if(!in[i])DP::ae(0,i);
	DP::dfs(0);
	for(int i=0;i<=m;i++)res=max(res,f[0][i]);
	printf("%d\n",res);
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14596927.html