• 二叉树问题(区间DP好题)


    二叉树问题

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    Petya Bulochkin很幸运:他得到了一份在“Macrohard”公司的工作。他想要展现他的才华,所以他要把他第一份工作做得尽可能好。这个任务是写一个搜索引擎。Petya知道一系列的整数A1,A2,……,Ak(k<=300, 1<=Ai<=10000000, Ai 都不相同)我们把这些数称作关键字。这个引擎应该要能回答这样的问题:“那里是不是有一个关键字是S?”我们已经知道,S是1到n(1<=n<=10000000)中任何一个整数。Petya决定使用排序二叉树来解决这个问题。
    我们把比较的次数称作费用C。例如,对于第三棵二叉树,我们有对于每一个S的查找费用:
    S 1 2 3 4 5 6 7 8 9 10 11
    C 2 3 3 3 3 3 1 2 2 2 2
    我们把对于s=1~n的费用和称作二叉树的费用,例如,第三棵二叉树的费用是2+3+3+3+3+3+1+2+2+2+2=26
    我们的任务是对于关键字A1~Ak,写出由这些关键字形成的二叉树中的最小费用。

    输入

    第一行是n,第二行是k,下面k行中第i行是Ai

    输出

    输出文件仅有一行包含一个整数表示要求的最小费用。

    样例输入

    10 4
    9 3 7 4

    样例输出

    22

    提示

    这个最小费用的二叉树指的是:

    题解:
    先拿样例来说,根据二叉搜索树的左小右大的性质,4~7都是查找2次,7~9都是查找3次,不难发现,查找次数相同的数都是以区间的形式存在的。
    因此判断这道题是区间DP,将n个数从小到大排序即可。
    确定了思路,现在让我们来看怎么定义状态,定义状态是这道题的难点,本人一开始简单的认为f[i][j]表示在区间i~j中查找数a[i]~a[j]的最小次数,发现后效性不可避免。后来听了点大佬的教导,其实正确的状态定义应该为f[i][j]表示在区间i~j中查找a[i-1]+1~a[j+1]-1的最小次数。(是不是很巧妙?)
    动规方程很简单f[j][i+j-1]=min(f[j][i+j-1],f[j][k-1]+(a[i+j]-a[j-1]-1));
    AC代码如下:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    using namespace std;
    int n,m;
    int a[501],f[501][501];
    int main()
    {
        int i,j,k;
        memset(f,127/3,sizeof(f));
        scanf("%d",&m);
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        a[0]=0;a[n+1]=m+1;
        for(i=1;i<=n;i++)
            f[i][i]=a[i+1]-a[i-1]-1;
        for(i=2;i<=n;i++)
        {
            for(j=1;j<=n-i+1;j++)
            {
                for(k=j;k<=i+j-1;k++)
                {
                    if(k==j)f[j][i+j-1]=min(f[j][i+j-1],f[k+1][i+j-1]+(a[i+j]-a[j-1]-1));
                    else if(k==i+j-1)f[j][i+j-1]=min(f[j][i+j-1],f[j][k-1]+(a[i+j]-a[j-1]-1));
                    else f[j][i+j-1]=min(f[j][i+j-1],f[j][k-1]+f[k+1][i+j-1]+(a[i+j]-a[j-1]-1));
                }
            }
        }
        cout<<f[1][n];
        return 0;
    }
    特别感谢,@SilverWolf
  • 相关阅读:
    <数据挖掘导论>读书笔记8FP树
    <数据挖掘导论>读书笔记7 Apriori算法
    c#:Json字符串转成xml对象
    微信公众平台开发
    一维随机变量及其概率分布
    概率的基本概念
    C#调用OCR组件识别图片文字
    增加系统右键菜单
    visual studio内置“iis”组件提取及二次开发
    《JavaScript权威指南》读书笔记——JavaScript核心
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/7002005.html
Copyright © 2020-2023  润新知