zoukankan      html  css  js  c++  java
  • CSUOJ-1980 不堪重负的数(区间dp)

    1980: 不堪重负的树

            Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 57     Solved: 20    


    Description

    小X非常喜欢树,然后他生成了一个大森林给自己玩。
    玩着玩着,小X陷入了沉思。

    • 一棵树由N个节点组成,编号为i的节点有一个价值Wi。
    • 假设从树根出发前往第i个节点(可能是树根自己),一共需要经过Di个节点(包括起点和终点),那么这个节点对这棵树产生的负担就是Di与Wi的乘积。
    • 对于一棵树而言,这棵树的负担值为所有节点对它产生的负担之和。

    小X学习了dfs,如果他知道树的结构,他当然可以很容易地算出树的负担值。可是现在沉思中的小X并不知道树的结构形态,他只知道一棵二叉树的中序遍历以及每个节点的价值,那么这棵二叉树可能的最小负担值是多少呢?

    Input

    第一行为一个正整数T(T≤20)表示数据组数。
    每组数据包括三行。
    第一行为一个正整数N(N≤200)。
    第二行为N个正整数Wi(Wi≤108),表示编号为i的节点的价值。
    第三行为N个正整数Pi(Pi≤N),为一个1~N的排列,表示二叉树的中序遍历结果。

    Output

    对于每组数据,输出一行一个正整数,表示这棵树可能的最小负担值。

    Sample Input

    2
    4
    1 2 3 4
    1 2 3 4
    7
    1 1 1 1 1 1 1
    4 2 3 5 7 1 6
    

    Sample Output

    18
    17
    

    Hint

    对于第一个样例,树根为3,3的左儿子是2,3的右儿子是4,2的左儿子是1,这样构成的树可以达到最小负担。
    对于第二个样例,对应的满二叉树可以达到最小负担。

    Source

    2017年8月月赛

    Author

    devember

    解题思路:重点是理解中序遍历,先左子树、然后根节点、然后右子树。找出状态转移方程:dp[i][j] = min(dp[i][k-1]+dp[k+1][j]+a[j]-a[i-1],dp[i][j])然后枚举断点k(也就是根)就行。
    做完觉得dp.区间dp和dfs还不太会。。所以重新看了下。想起来之前8月月赛这题刚好就是这个还不会。就做了。。。发现算法这东西,主要还是理解他的本质基础,这样比较容易掌握。。(虽然我还是菜鸡- -)
     
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=205;
    const long long INF=1e18;
    long long a[maxn],w[maxn];
    long long dp[maxn][maxn];
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n,m;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&w[i]);
            }
            a[0] = 0;
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&m);
                a[i] = a[i-1] + w[m]; //求前缀和
                dp[i][i] = w[m];
            }
            for(int l=2;l<=n;l++)
            {
                for(int i=1;i+l-1<=n;i++)
                {
                    int j = i+l-1;
                    dp[i][j] = INF;
                    for(int k=i;k<=j;k++)//枚举根
                    {
                        long long temp = dp[i][k-1]+dp[k+1][j]+a[j]-a[i-1];
                        if(temp<dp[i][j])
                            dp[i][j] = temp;
    
                    }
                }
            }
            printf("%lld
    ",dp[1][n]);
        }
    }

    哎。。前面好多算法都忘了。。当初就理解的不够透彻。。

  • 相关阅读:
    关于动态规划的问题494_LEETCODE_TARGET_SUM
    Python 关于二叉树生成、先序遍历、中序遍历、后序遍历、反转
    关于python引入文件路径的解决办法
    git一些笔记
    迪克斯特拉 算法(算最短距离)
    Python多线程编程中daemon属性的作用
    types.MethodType实例绑定方法
    Python之__getitem__、__getattr__、__setitem__ 、__setitem__ 的区别
    jenkins自动打包ios、安卓
    python socket编程tcp/udp俩连接
  • 原文地址:https://www.cnblogs.com/WWkkk/p/7435684.html
Copyright © 2011-2022 走看看