• [HAOI2010] 软件安装


    题目类型:(tarjan)缩点+树形(dp)

    传送门:>Here<

    题意:给出N各节点,每个节点是一个软件,该软件有占用空间(W[i])和价值(V[i])。软件之间有依赖关系,如果想要运行(i),就必须安装(d[i])。问总空间不超过(M)时,运行的最大价值

    解题思路

    首先读题要仔细——安装和运行在这里是两个概念。安装相当于去选择一个软件集合,而在选择完所有的以后才能开始运行。我们可以选择建图,从(d[i])(i)连边。通过读题不难发现所有节点的入度都不超过1。因此对于每一个连通块,要么是一个环,要么是一个(DAG)。而对于一个环,要么全部安装并运行,要么全部不安装(不可能安装一部分的环)。因此自然而然的,我们可以把环看做一个点,因此首先进行缩点。

    缩点完了之后,整张图就变成了一个多个连通块的(DAG)。由于不存在环,每个连通块有且仅有存在入度为0的点。从一个虚拟根节点像所有入度为0的点连边,就形成了一个联通的(DAG)——由于入度不超过1,可以将其看做一棵树。

    于是问题转化为树上的01背包,前提是要选子树的话必须选择该子树的根节点。

    考虑树形背包的做法(这一点非常关键)。一般我们都令(dp[u][j])表示以(u)为根节点的子树中,总空间设定为(j)时的最大价值。然而这样的定义经常使人受到误导——这让人觉得很难转移。

    实际上我们定义的原型应该是(dp[u][i][j])表示以(u)为根节点的子树中,前(i)棵子树中,总空间设定为(j)时的最大价值。因此我们有状态转移方程$$dp[u][i][j]=Max{dp[u][i-1][j],dp[u][i-1][j-k]+dp[v][all][k]}$$那为什么在普通的定义中没有(i)呢?因为(i)已经通过滚动数组优化了

    这个方程的实质是爆扫——枚举当前子树分配到的空间,剩下的空间给之前的。但是这里有一个特殊的点,就是根节点必须选。这就意味着(dp[u][i-1][j-k])必须包含根节点,其实质也就是(j-k geq W[u])。这样每次转移的时候不至于让根节点消失了。

    反思

    读题是非常重要的。不误解题目意思是做出这道题的关键。当然考虑如何必须选根节点来推方程这方面好像还没什么经验,对于(dp)还是要多加练习啊。

    Code

    注意这是一个01背包。由于我们采用滚动数组优化,无论这是不是在树上,外层的(j)都是需要倒扫的。(当前一轮取决于上一轮比自己小的,正扫就会覆盖)

    /*By DennyQi 2018*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN = 110;
    const int MAXM = 510;
    const int INF = 1061109567;
    inline int Max(const int a, const int b){ return (a > b) ? a : b; }
    inline int Min(const int a, const int b){ return (a < b) ? a : b; }
    inline int read(){
        int x = 0; int w = 1; register char c = getchar();
        for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
        if(c == '-') w = -1, c = getchar();
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
    }
    int N,M,dfs_clock,top;
    int w[MAXN],v[MAXN],d[MAXN];
    int _first[MAXN],_nxt[MAXM],_to[MAXM],_cnt;
    int dfn[MAXN],low[MAXN],sta[MAXN],sccno[MAXN],scc_cnt;
    int W[MAXN],V[MAXN],rd[MAXN];
    int first[MAXN],nxt[MAXN],to[MAXN],cnt;
    int dp[MAXN][50010];
    inline void _add(int u, int v){
    	_to[++_cnt] = v, _nxt[_cnt] = _first[u], _first[u] = _cnt;
    }
    inline void add(int u, int v){
    	to[++cnt] = v, nxt[cnt] = first[u], first[u] = cnt;
    }
    void tarjan(int u){
    	int _v;
    	dfn[u] = low[u] = ++dfs_clock;
    	sta[++top] = u;
    	for(int i = _first[u]; i; i = _nxt[i]){
    		_v = _to[i];
    		if(!dfn[_v]){
    			tarjan(_v);
    			low[u] = Min(low[u], low[_v]);
    		}
    		else if(!sccno[_v]){
    			low[u] = Min(low[u], dfn[_v]);
    		}
    	}
    	if(low[u] == dfn[u]){
    		++scc_cnt;
    		while(1){
    			sccno[sta[top]] = scc_cnt;
    			W[scc_cnt] += w[sta[top]];
    			V[scc_cnt] += v[sta[top]];
    			--top;
    			if(sta[top+1] == u){
    				break;
    			}
    		}
    	}
    }
    void DP(int u){
    	for(int j = W[u]; j <= M; ++j){
    		dp[u][j] = V[u];
    	}
    	int v;
    	for(int i = first[u]; i; i = nxt[i]){
    		v = to[i];
    		DP(v);
    		for(int j = M; j >= W[u]; --j){
    			for(int k = 0; k <= j-W[u]; ++k){
    				dp[u][j] = Max(dp[u][j], dp[u][j-k] + dp[v][k]);
    			}
    		}	
    	}
    	
    }
    int main(){
    //	freopen(".in","r",stdin);
    	N = read(), M = read();
    	for(int i = 1; i <= N; ++i) w[i] = read();
    	for(int i = 1; i <= N; ++i) v[i] = read();
    	for(int i = 1; i <= N; ++i){
    		d[i] = read();
    		if(d[i]){
    			_add(d[i], i);
    		}
    	}
    	for(int i = 1; i <= N; ++i){
    		if(!dfn[i]){
    			tarjan(i);
    		}
    	}
    	for(int i = 1; i <= N; ++i){
    		if(sccno[i] != sccno[d[i]] && d[i]){
    			add(sccno[d[i]], sccno[i]);
    			++rd[sccno[i]];
    		}
    	}
    	for(int i = 1; i <= scc_cnt; ++i){
    		if(rd[i] == 0){
    			add(N+1, i);
    		}
    	}
    	DP(N+1);
    	printf("%d", dp[N+1][M]);
    	return 0;
    }
    
  • 相关阅读:
    zoj 1239 Hanoi Tower Troubles Again!
    zoj 1221 Risk
    uva 10192 Vacation
    uva 10066 The Twin Towers
    uva 531 Compromise
    uva 103 Stacking Boxes
    稳定婚姻模型
    Ants UVA
    Golden Tiger Claw UVA
    关于upper、lower bound 的探讨
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9854269.html
Copyright © 2020-2023  润新知