zoukankan      html  css  js  c++  java
  • poj_2486 动态规划

    题目大意

        N个节点构成一棵树,每个节点上有一个权重val[i], 从根节点root出发在树上行走,行走的时候只能沿着树枝行进。最多在树上走k步,每第一次到达某个节点j,可以获得val[j]的收益,求从root出发,最多走k步,可以得到的最大收益。

    题目分析

        树形结构+ 最优化问题,考虑使用动态规划来解决,树形动态规划的dp状态,第一维 dp[i][...]一般是指从i节点出发或者以i节点为根的xxxx。 
    /*dp[i][j][0] 表示从节点i出发,走j步,最终回到i节点,所能得到的最大收益 
    dp[i][j][1] 表示从节点i出发,走j步,最终不回到i节点,所能得到的最大收益 
    显然有: 
    (1)从i出发走j步回到i得到的最大收益 vs 依次枚举i的子节点son,从i出发走 j-k步回到i(其中不包括son节点),再 
    加上从son出发走k-2步,回到son节点,再加上i-->son 和 son-->i 的两步 
    dp[i][j][0] = max(dp[i][j][0], dp[i][j-k][0] + dp[son][k-2][0] + val[son])

    (2)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步回到i(其中不包括son节点),再 
    加上从son出发走k-1步,不回到son节点,再加上i-->son的一步 
    dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][0] + dp[son][k-1][1] +val[son]);

    (3)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步不回到i(其中不包括son节点),再 
    加上从son出发走k-2步,回到son节点,再加上i-->son和son-->i 的两步 
    dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);

    以dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);为例,是否需要考虑 son节点走k-2步 
    和从son的父节点i开始走j-k步的重合? 答案是不需要,因为按照父节点i的子节点顺序,依次枚举son节点,在枚举到当前的son节点时, 
    dp[i][j-k][1]中不包含当前的son的贡献 
    */

    实现(c++)

    #include<stdio.h>
    #include<string.h>
    #define MAX_NODE_NUM 205
    #define MAX_STEP_NUM 205
    #define max(a, b) a>b? a:b
    
    /*dp[i][j][0] 表示从节点i出发,走j步,最终回到i节点,所能得到的最大收益
    dp[i][j][1] 表示从节点i出发,走j步,最终不回到i节点,所能得到的最大收益
    显然有: 
    (1)从i出发走j步回到i得到的最大收益 vs  依次枚举i的子节点son,从i出发走 j-k步回到i(其中不包括son节点),再
    加上从son出发走k-2步,回到son节点,再加上i-->son 和 son-->i 的两步
    dp[i][j][0] = max(dp[i][j][0], dp[i][j-k][0] + dp[son][k-2][0] + val[son])
    
    (2)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步回到i(其中不包括son节点),再
    加上从son出发走k-1步,不回到son节点,再加上i-->son的一步
    dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][0] + dp[son][k-1][1] +val[son]);
    
    (3)从i出发走j步不回到i得到最大收益 vs 从i出发走 j-k步不回到i(其中不包括son节点),再
    加上从son出发走k-2步,回到son节点,再加上i-->son和son-->i 的两步
    dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);
    
    
    以dp[i][j][1] = max(dp[i][j][1], dp[i][j-k][1] + dp[son][k-2][0] + val[son]);为例,是否需要考虑 son节点走k-2步
    和从son的父节点i开始走j-k步的重合? 答案是不需要,因为按照父节点i的子节点顺序,依次枚举son节点,在枚举到当前的son节点时,
    dp[i][j-k][1]中不包含当前的son的贡献
    */
    int dp[MAX_NODE_NUM][MAX_STEP_NUM][2];
    int val[MAX_NODE_NUM];
    int  n, k;
    
    struct Edge{
    	int v;		//v表示该边所指向的子节点
    	int next;	//next表示该边的兄弟边的索引
    	Edge(int vv = -1, int nn = -1):
    	v(vv), next(nn){
    	}
    };
    
    Edge gEdges[2*MAX_NODE_NUM];  //利用静态数组构建 多叉树
    int gEdgeIndex;
    int gHead[MAX_NODE_NUM]; //gHead[i] 表示节点i的最右边的子节点,初始时均为 -1
    
    void InsertEdge(int u, int v){ //因为不能确定u和v在最终的树中哪个是父节点哪个是子节点
    								//因此分别将u和v作为父节点和子节点,形成边
    	gEdges[gEdgeIndex].v = v;
    	gEdges[gEdgeIndex].next = gHead[u];
    	gHead[u] = gEdgeIndex++;
    }
    
    void Init(int n, int k){
    	for (int i = 1; i <= n; i++){
    		gHead[i] = -1;
    		for (int j = 1; j <= k; j++){
    			dp[i][j][0] = dp[i][j][1] = 0;
    		}
    	}
    	gEdgeIndex = 0;
    }
    
    void Dfs(int u, int father){
    	for (int i = gHead[u]; i != -1; i = gEdges[i].next){
    		int v = gEdges[i].v;
    		if (v == father)	//对于两个节点u和v,有u-->v的边,也有v-->u的边,为了避免死循环
    			continue;
    		Dfs(v, u);
    
    		for (int j = k; j >= 0; --j){
    			for (int t = 1; j + t <= k; ++t){
    				dp[u][j + t][0] = max(dp[u][j + t][0], dp[u][j][1] + dp[v][t - 1][0] + val[v]);
    				if (t >= 2)dp[u][j + t][0] = max(dp[u][j + t][0], dp[u][j][0] + dp[v][t - 2][1] + val[v]);
    				if (t >= 2)dp[u][j + t][1] = max(dp[u][j + t][1], dp[u][j][1] + dp[v][t - 2][1] + val[v]);
    			}
    		}
    	}
    }
    int main(){
    	int u, v;
    	while (scanf("%d %d", &n, &k) != EOF){
    		Init(n, k);
    		for (int i = 1; i <= n; i++)
    			scanf("%d", &val[i]);
    		for (int i = 1; i < n; i++){
    			scanf("%d %d", &u, &v);
    			InsertEdge(u, v);
    			InsertEdge(v, u);
    		}
    		Dfs(1, -1);
    		printf("%d
    ", dp[1][k][0] + val[1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android组件化路由实践
    RecyclerView实现Gallery画廊效果
    ReactNative实现GridView
    [Java][Servlet] Cannot call sendRedirect() after the response has been committed
    [Java][Servlet] Failed to destroy end point associated with ProtocolHandler ["http-nio-8080"]
    [Environment Build] Win10下配置Apach Tomcat
    [Java][Liferay] File system in liferay
    [Java][Liferay] 解决在Linux系统中liferay-ext项目无法卸载的问题
    [Coding Style] CSS coding style
    [JQuery] Using skill in JQuery
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4857313.html
Copyright © 2011-2022 走看看