• 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
  • 相关阅读:
    在VMware9.0上安装CentOS6.3+mysql5.5.28数据库 东师理想
    Python学习总结(二)python的练习方法
    gdb调试nasm语法的汇编程序(转载)
    配置Bochs
    量变与质变(生活中,技术上)
    设置gdb反汇编语法为intel(转载)
    Python学习总结(一)
    2012暑假计划
    理解TCP为什么需要进行三次握手(白话)(转载)
    对自己的学习方式的思考(转载)
  • 原文地址:https://www.cnblogs.com/icodefive/p/4311287.html
Copyright © 2020-2023  润新知