zoukankan      html  css  js  c++  java
  • 【题解】NOI2009二叉查找树 + NOIP2003加分二叉树

      自己的思维能力果然还是太不够……想到了这棵树所有的性质即中序遍历不变,却并没有想到怎样利用这一点。在想这道题的过程中走入了诸多的误区,在这里想记录一下 & 从中吸取到的教训(原该可以避免的吧)。

      1. 注意到了中序遍历不变的性质却不会使用。

      2. 注意到只有相对大小才会影响树的形态,在考虑的时候一直在想如何改变一个数的位置关系,分析修改权值对于树产生的影响。但这样是很难分析的,将树看作一个整体也不利于dp状态的划分。

      3. 想不出怎样计算一个节点的深度(不能快速找到一个节点所处的位置)。

      正确的思维应当是:

      1.中序遍历不变 ---> 数值排名位于 [l, r] 这个区间中的所有树必然可能同在一棵子树中(且这棵子树中不含其他的节点);

      2.不好计算一个节点插入的深度 / 不好修改一个数在子树中的位置:改修改为插入。整棵子树中,唯一一个容易确定位置的节点:若这个节点是当前子树中权值最小的,则这个节点为子树的根,其余所有节点的深度 ++;

      于是正确的 dp 状态就出来了。(dp[l][r][v]) 表示 (l) 到 (r) 的区间所有节点 ( >= v ) 的最小代价。转移方程分别为两种:修改该节点权值 & 不修改该节点权值。

        (dp[l][r][v] = dp[l][k - 1][v] + dp[k + 1][r][v] + K + sum[l][r];)

        (dp[l][r][v] = dp[l][k - 1][P[i].v] + dp[k + 1][r][P[i].v] + sum[l][r];)

      其中,第二个转移方程中要求 (P[i].v >= v),(P[i].v) 是节点原本的权值,(sum[l][r]) 为区间 (l -> r) 的访问频率。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 100
    #define int long long
    #define INF 999999999999LL
    int n, K, sum[maxn];
    int ans = INF, dp[maxn][maxn][maxn];
    
    struct node
    {
        int num, v, w;
    }P[maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    bool cmp(node a, node b) { return a.v < b.v; }
    bool cmp1(node a, node b) { return a.num < b.num; }
    void gmin(int &x, int y) { x = x < y ? x : y; }
    
    int dfs(int l, int r, int v)
    {
        if(~dp[l][r][v]) return dp[l][r][v];
        else dp[l][r][v] = INF;
        if(l > r) return dp[l][r][v] = 0;
        for(int k = l; k <= r; k ++) 
        {
            gmin(dp[l][r][v], dfs(l, k - 1, v) + dfs(k + 1, r, v) + K + sum[r] - sum[l - 1]);
            if(P[k].v >= v) gmin(dp[l][r][v], dfs(l, k - 1, P[k].v) + dfs(k + 1, r, P[k].v) + sum[r] - sum[l - 1]);
        }
        return dp[l][r][v];
    }
    
    signed main()
    {
        n = read(), K = read();
        memset(dp, -1, sizeof(dp));
        for(int i = 1; i <= n; i ++) P[i].num = read();
        for(int i = 1; i <= n; i ++) P[i].v = read();
        for(int i = 1; i <= n; i ++) P[i].w = read();
        sort(P + 1, P + 1 + n, cmp);
        for(int i = 1; i <= n; i ++) P[i].v = i;
        sort(P + 1, P + 1 + n, cmp1);
        for(int i = 1; i <= n; i ++) sum[i] += sum[i - 1] + P[i].w;
        ans = min(ans, dfs(1, n, 1));
        printf("%lld
    ", ans);
        return 0;
    } 

       2. 加分二叉树

      双倍经验……

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 40
    #define int long long 
    int n, a[maxn];
    int f[maxn][maxn], dp[maxn][maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    int dfs(int l, int r)
    {
        if(dp[l][r]) return dp[l][r];
        if(l > r) return dp[l][r] = 1;
        if(l == r) return  f[l][r] = l, dp[l][r] = a[l];
        for(int k = l; k <= r; k ++)
        {
            int x = dfs(l, k - 1), y = dfs(k + 1, r);
            if(dp[l][r] < x * y + a[k])
            {
                dp[l][r] = x * y + a[k];
                f[l][r] = k; 
            }
        }
        return dp[l][r];
    }
    
    void Get_ans(int l, int r)
    {
        if(l > r) return;
        printf("%lld ", f[l][r]);
        Get_ans(l, f[l][r] - 1), Get_ans(f[l][r] + 1, r);
    }
    
    signed main()
    {
        n = read();
        for(int i = 1; i <= n; i ++) a[i] = read(); 
        printf("%lld
    ", dfs(1, n));
        Get_ans(1, n); puts("");
        return 0;
    }
  • 相关阅读:
    Ubuntu 16 安装redis客户端
    crontab 参数详解
    PHP模拟登录发送闪存
    Nginx配置端口访问的网站
    Linux 增加对外开放的端口
    Linux 实用指令之查看端口开启情况
    无敌的极路由
    不同的域名可以指向同一个项目
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
    Redis 创建多个端口
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9072639.html
Copyright © 2011-2022 走看看