• poj2486


    题目大意:给出一个树,每个节点有一个值,问从1开始走走k步最多能遍历到最大的值的和;
    dp[i][j][k] 当i为零是表示如果从j点开始遍历以j为跟的子树,走k步后回到原点的最大值。
    dp[i][j][k] 当i为零是表示如果从j点开始遍历以j为跟的子树,走k步后不回到原点的最大值。

    我们知道的是如果能走k步最大值为maxa那么走j>k步至少为maxa,所以每次用子树的和当前节点做背包,0+0= 0,0+1=1,1+0=1;

    由于避免重复我是用了一个类似于滚动数组的东西处理的背包部分,但是我后来发现那样好蠢还不好写还费时其实将一类中的某一个放入背包中完全能将背包倒过来然后每到一格将所有的东西装进去就行了。

    第一次的代码是这样的

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    const int maxa = 1000;
    const int maxn = 1000000;
    int dp[2][maxa][maxa];//0表示能回到当前位置,1表示不回到
    int edge[maxa][maxa];
    int vv[maxa];
    int num[maxa];
    int n, p;
    int dp1[maxa];
    //#define max(a,b) a>b?a:b
    void dfs(int a, int fa){
        for(int i = 0; i  < num[a]; i++){
            int k = edge[a][i];
            if(k != fa){
                dfs(k, a);
            }
        }
        for(int i = 0; i <= p; i++)
            dp[1][a][i] = dp[0][a][i] = vv[a];
        for(int u = 0; u < num[a]; u++){
            int v = edge[a][u];
            if(v != fa){
                for(int i = 0; i <= p; i++)
                    dp1[i] = vv[a];
                for(int i = 0; i <= p; i++){
                    for(int k = 0; k <= p; k++){
                        if(i + k +2 <= p){
                            dp1[i+k+2] = max(dp1[i+k+2], dp[1][a][i]+dp[0][v][k]);
                        }
                        if(i+k+1 <= p)
                            dp1[i+k+1] = max(dp1[i+k+1], dp[0][a][i]+dp[1][v][k]);
                    }
                }
                for(int i =  0; i <= p; i++){
                    dp[1][a][i] = max(dp[1][a][i], dp1[i]);
                }
                for(int i = 0; i <= p; i++)
                    dp1[i] = vv[a];
                for(int i = 0; i <= p; i++){
                    for(int k = 0; k <= p; k++){
                        if(i+k+2 <= p){
                            dp1[i+k+2] = max(dp1[i+k+2],dp[0][a][i]+ dp[0][v][k]);
                        }
                    }
                }
                for(int i = 0; i <= p; i++){
                    dp[0][a][i] = max(dp[0][a][i],dp1[i]);
                }
            }
        }
    }
    int main(){
        while(scanf("%d%d", &n, &p)!=EOF){
            int a, b;
            memset(num, 0, sizeof(num));
            for(int i = 1; i <= n; i++){
                scanf("%d", &vv[i]);
            }
            for(int i = 1; i < n; i++){
                scanf("%d%d", &a, &b);
                edge[a][num[a]++] = b;
                edge[b][num[b]++] = a;
            }
            //memset(dp, 0, sizeof(dp));
            dfs(1, 0);
            printf("%d
    ", dp[1][1][p]);
        }
    }
    /*
    8 6
    1 1 1 1 1 1 1 4
    1 2
    1 3
    1 4
    1 5
    1 6
    1 7
    1 8
    */
    View Code

    改后是这样的

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    const int maxa = 1000;
    const int maxn = 1000000;
    int dp[2][maxa][maxa];//0表示能回到当前位置,1表示不回到
    int edge[maxa][maxa];
    int vv[maxa];
    int num[maxa];
    int n, p;
    //#define max(a,b) a>b?a:b
    void dfs(int a, int fa){
        for(int i = 0; i  < num[a]; i++){
            int k = edge[a][i];
            if(k != fa){
                dfs(k, a);
            }
        }
        for(int i = 0; i <= p; i++)
            dp[1][a][i] = dp[0][a][i] = vv[a];
        for(int u = 0; u < num[a]; u++){
            int v = edge[a][u];
            if(v != fa){
                for(int i = p; i >= 0; i--){
                    for(int k = 0; k <= i; k++){
                        if(i - k- 2 >= 0){
                            dp[1][a][i] = max(dp[1][a][i], dp[1][a][k]+dp[0][v][i-k-2]);
                            dp[0][a][i] = max(dp[0][a][i], dp[0][a][k]+dp[0][v][i-k-2]);
                        }if(i - k - 1 >= 0){
                            dp[1][a][i] = max(dp[1][a][i], dp[0][a][k]+dp[1][v][i-k-1]);
                        }
                    }
                }
            }
        }
    }
    int main(){
        while(scanf("%d%d", &n, &p)!=EOF){
            int a, b;
            memset(num, 0, sizeof(num));
            for(int i = 1; i <= n; i++){
                scanf("%d", &vv[i]);
            }
            for(int i = 1; i < n; i++){
                scanf("%d%d", &a, &b);
                edge[a][num[a]++] = b;
                edge[b][num[b]++] = a;
            }
            //memset(dp, 0, sizeof(dp));
            dfs(1, 0);
            printf("%d
    ", max(dp[1][1][p], dp[0][1][p]));
        }
    }
    /*
    8 6
    1 1 1 1 1 1 1 4
    1 2
    1 3
    1 4
    1 5
    1 6
    1 7
    1 8
    */
    View Code
  • 相关阅读:
    tasker支持的shell 命令大全
    crx 文件安装 如何安装 Chrome插件
    python mac地址计算
    Java线程池
    springMVC请求过程
    java中特殊的String类型
    单例模式和多例模式
    hash算法学习
    arraylist和linkedlist的简单比较
    乐观锁和悲观锁
  • 原文地址:https://www.cnblogs.com/icodefive/p/4311287.html
Copyright © 2020-2023  润新知