zoukankan      html  css  js  c++  java
  • dp (1)

     

    D - Tree of Tree ZOJ - 3201 

    这个题目我开始是这么定义的dp[i][j][0] dp[i][j][1] 表示对于第i个节点还有j个的选择 0 代表不选这个节点,1 代表选这个节点。

    然后我写了,对题目理解出现了偏差写出来一个错误的,然后正确理解题意发现这样子写好麻烦。转移方程很难写。

    上网搜题解,网上基本上都是这么定义的 dp[i][j]表示选第 i 个节点该子树的节点数为  j  的最大带权值。

    所以这个就可以变成一个树形dp+01背包。

    这个状态转移方程应该就是 dp[u][j]=max(dp[u][j] ,dp[u][j-k]+dp[v][k])  其实我觉得这个转移方程也没有那么好想。

    这个01背包就是在枚举以u为根节点的这棵树的每一颗子树取多少个节点。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 1e5 + 10;
    int dp[200][200];
    vector<int>G[200];
    int n, k;
    
    void dfs(int u,int pre)
    {
        for (int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if (v == pre) continue;
            dfs(v, u);
            for (int j = k; j >= 1; j--)
            {
                for (int h = 0; h < j; h++)
                {
                    dp[u][j] = max(dp[u][j], dp[u][j - h] + dp[v][h]);
                }
            }
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            memset(dp, 0, sizeof(dp));
            for (int i = 0; i <= n; i++) G[i].clear();
            for (int i = 0; i < n; i++) {
                scanf("%d", &dp[i][1]);
            }
            for(int i=1;i<n;i++)
            {
                int u, v;
                scanf("%d%d", &u, &v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            dfs(0, -1);
            int ans = 0;
            for(int i=0;i<n;i++)
            {
                ans = max(ans, dp[i][k]);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    树形dp

    C - Brackets POJ - 2955 

    这个题目其实我觉得很像就是在求回文,所以和那个兔子的题目很像,但是呢,还是有一点点的不同

    回忆一下兔子的题目  兔子传送门

    这个题目的状态转移方程也就是

    if(条件判断) dp[i][j]=max(dp[i+1][dp[j-1]+2,dp[i][j])

    else dp[i][j]=max(dp[i+1][j],dp[i][j-1])

    这个题目还有一个地方,就是因为我们定义的dp[i][j]表示从i到j的最大的匹配了的数量,所以呢,()()()

    这种情况,如果你值是进行状态转移,那就会出现问题了,

    因为dp[1][2]=2 dp[2][3]=1 dp[3][4]=2  所以 dp[1][4]=dp[2][3]+2这个就不对了,这个时候,我们应该找一个切断点。

    dp[1][4]的切断点就是dp[1][2]+dp[3][4]=4

    所以说还有有一个for循环来找这个断点,这个我也没想明白是看题解的。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #define inf 0x3f3f3f3f
    using namespace std;
    int dp[200][200];
    char s[200];
    
    int main()
    {
        while(scanf("%s",s+1)!=EOF)
        {
            if (s[1] == 'e') break;
            memset(dp, 0, sizeof(dp));
            int len = strlen(s + 1);
            int ans = 1;
            for(int i=2;i<=len;i++)
            {
                for(int j=1;j+i-1<=len;j++)
                {
                    int ends = i + j - 1;
                    if ((s[j]=='('&&s[ends]==')')||(s[j]=='['&&s[ends]==']')) dp[j][ends] =dp[j + 1][ends - 1] + 2;
                    else dp[j][ends] = max(dp[j + 1][ends], dp[j][ends - 1]);
                    for (int k = j; k < ends; k++) dp[j][ends] = max(dp[j][ends], dp[j][k] + dp[k+1][ends]);
                    //printf("j %c ends %c dp[%d][%d]=%d
    ", s[j],s[ends],j, ends, dp[j][ends]);
                }
            }
            printf("%d
    ", dp[1][len]);
        }
        return 0;
    }
    区间dp

    Q - 最大报销额HDU - 1864 

    这个题目我感觉还比较简单啊,就是字符串处理要注意一下,可以看我的另外一篇博客用sscanf的方法来处理很方便。

    https://www.cnblogs.com/EchoZQN/p/10830015.html

    处理完之后就是一个简单的01背包,需要注意的是因为有小数,所以*100转化成整数来处理即可。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn = 3e6 + 10;
    int dp[maxn], n, m;
    int a[100];
    double q;
    
    int main()
    {
        while(scanf("%lf%d",&q,&m)!=EOF)
        {
            if (m == 0) break;
            n = (int)(q * 100);
            int tot = 0;
            for(int k=1;k<=m;k++)
            {
                int num;
                scanf("%d", &num);
                char ch, cs[110];
                double mon;
                int A = 0, B = 0, C = 0, flag = 0;
                for(int i=1;i<=num;i++)
                {
                    scanf("%s", cs);
                    sscanf(cs, "%c:%lf", &ch, &mon);
                    int mm = (int)(mon * 100);
                    if (ch == 'A') A += mm;
                    else if (ch == 'B') B += mm;
                    else if (ch == 'C') C += mm;
                    else flag = 1;
                    if (A > 60000 || B > 60000 || C > 60000 || (A + B + C) > 100000) flag = 1;
                //    printf("%d %d %d
    ", A, B, C);
                }
                if (flag == 0) a[++tot] = A + B + C;
            }
            memset(dp, -inf, sizeof(dp));
            dp[0] = 0;
            //for (int i = 1; i <= tot; i++) printf("%d
    ", a[i]);
            //printf("n=%d
    ", n);
            for(int i=1;i<=tot;i++)
            {
                for(int j=n;j>=a[i];j--)
                {
                    dp[j] = max(dp[j], dp[j - a[i]]);
                }
            }
            //printf("%d
    ", dp[n]);
            int ans = 0;
            for(int i=n;i>=0;i--)
            {
                if(dp[i]>=0)
                {
                    ans = i;
                    break;
                }
            }
            printf("%.2lf
    ", ans*1.0 / 100);
        }
        return 0;
    }
    01背包

    这个就是今天的dp训练了,接下来就是复习以前的算法。

  • 相关阅读:
    【php-04控制流程】
    【php-03函数】
    【php-02-变量】
    【php-01-标记符】
    【CSS 基础面试题】
    【CSS3特效之转化(transform)和过渡(transition)】
    【jsonp】
    【PHP 面试知识梳理】
    OM模块功能&API详解
    EBS 多SHEET页EXCEL动态报表开发过程
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/10994493.html
Copyright © 2011-2022 走看看