• 【HAOI2010】软件安装


    需要安装n个软件,每个软件会占用wi的空间,价值为vi
    计算机总容量为M,要使这些软件的价值尽可能大
    但软件之间存在依赖关系,即只有安装了前提软件,这个软件才有价值
    求出结果
    

    如果只是普通的依赖关系,那么这些关系构成了一棵树
    显然使用树形dp,(dp[i][j])表示以 (i) 为根的子树中使用不超过 (j) 的空间的最大价值

    然而,由于原题面中说得很清楚(当然我这里简化版的题面看不出来……)
    依赖关系可能会成一个环
    比如,玩东方project的时候需要使用符卡练习器,否则连Easy难度都过不去, 这游戏就没有意义
    然而如果只下载符卡练习器,而不安装东方project,这个练习器毫无意义,价值也为0
    在上面这个例子里,东方project和符卡练习器互相依赖,成一个环
    我们要做的就是,把这些成环的依赖关系看待成一个点,使其等价于原来的多个程序

    缩点?
    tarjan准备上啊

    缩完以后就是一个简单地树形dp了,思路如上

    代码:

    #include<bits/stdc++.h>
    #define N 2005
    using namespace std;
    
    int n,m;
    int w[N],v[N],x[N],y[N];
    
    struct Edge
    {
    	int next,to;
    }edge[N<<2];
    int cnt=0,head[N];
    
    inline void add_edge(int from,int to)
    {
    	edge[++cnt].next=head[from];
    	edge[cnt].to=to;
    	head[from]=cnt;
    }
    
    template<class T>inline void read(T &res)
    {
    	char c;T flag=1;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    
    int tms=0,low[N],dfn[N],color[N];
    int sta[N],top=0;
    bool vis[N];
    int colorcnt=0;
    void tarjan(int u)
    {
    	low[u]=dfn[u]=++tms;
    	sta[++top]=u;
    	vis[u]=1;
    	for(register int i=head[u];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(!dfn[v])
    		{
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(vis[v])
    		{
    			low[u]=min(low[u],dfn[v]);
    		}
    	}
    	if(dfn[u]==low[u])
    	{
    		++colorcnt;
    		vis[u]=0;
    		while(sta[top+1]!=u)
    		{
    			color[sta[top]]=colorcnt;
    			vis[sta[top--]]=0;
    		}
    	}
    }
    
    int ww[N],vv[N],idx[N];
    int dp[N][N];
    void dfs(int u)
    {
    	for(register int i=ww[u];i<=m;++i) dp[u][i]=vv[u];
    	for(register int i=head[u];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		dfs(v);
    		for(register int j=m-ww[u];j>=0;--j)
    		{
    			for(register int k=0;k<=j;++k)
    				dp[u][j+ww[u]]=max(dp[u][j+ww[u]],dp[u][j+ww[u]-k]+dp[v][k]);
    
    		}
    	}
    }
    
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<=n;++i) read(w[i]);
    	for(register int i=1;i<=n;++i) read(v[i]);
    	for(register int i=1;i<=n;++i)
    	{
    		read(y[i]);
    		if(!y[i]) continue;
    		add_edge(y[i],i);
    	}
    	for(register int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    	memset(edge,0,sizeof(edge));
    	memset(head,0,sizeof(head));
    	for(register int i=1;i<=n;++i)
    	{
    		vv[color[i]]+=v[i];
    		ww[color[i]]+=w[i];
    		if(color[i]!=color[y[i]]&&y[i])
    		{	
    			add_edge(color[y[i]],color[i]);
    			idx[color[i]]++;
    		}
    	}
    	for(register int i=1;i<=colorcnt;++i)
    		if(!idx[i]) add_edge(colorcnt+1,i);
    	dfs(colorcnt+1);
    	printf("%d
    ",dp[colorcnt+1][m]);
    	return 0;
    }
    
  • 相关阅读:
    AngularJS指令的详解
    Linux(Ubuntu)下如何安装JDK
    Hibernate的三种状态
    JS是按值传递还是按引用传递
    git分支管理
    Hibernate注解映射联合主键的三种主要方式
    Linux下解决用户不能执行sudo的方法
    【GStreamer开发】GStreamer基础教程03——动态pipeline
    【GStreamer开发】GStreamer基础教程02——GStreamer概念
    【GStreamer开发】GStreamer基础教程02——GStreamer概念
  • 原文地址:https://www.cnblogs.com/tqr06/p/11623432.html
Copyright © 2020-2023  润新知