• 洛谷1040 加分二叉树


    原题链接

    挺水的一道区间(DP)
    (f[i][j])表示在中序遍历下编号(i sim j)的点所构成的子树的最高加分,枚举(k)为子树的根,则有状态转移方程:

    [f[i][j] = max limits _{k = i + 1} ^ {j - 1} { f[i][k - 1] imes f[k + 1][j] + f[k][k] } ]

    初始化(f[i][i])为点(i)的分数,(f[i][j] = f[i][i] + f[i + 1][j]),即左子树为空。
    因为题目并没有说清楚,实际上要求的前序遍历是所有解中字典序最小的,所以我们要尽量使得编号小的作为根或是左子树中的点,按编号从小到大枚举哪个作为根即可。
    求前序遍历可以定义(r[i][j])表示在中序遍历下编号(i sim j)的点所构成的子树的最高加分所选择的根,在(DP)过程中不断更新,最后递归输出即可。

    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int N = 50;
    ll f[N][N];
    int r[N][N];
    inline int re()
    {
    	int x = 0;
    	char c = getchar();
    	bool p = 0;
    	for (; c < '0' || c > '9'; c = getchar())
    		p |= c == '-';
    	for (; c >= '0' && c <= '9'; c = getchar())
    		x = x * 10 + c - '0';
    	return p ? -x : x;
    }
    void pr(int x, int y)
    {
    	if (x > y)
    		return;
    	printf("%d ", r[x][y]);
    	pr(x, r[x][y] - 1);
    	pr(r[x][y] + 1, y);
    }
    int main()
    {
    	int i, j, k, l, n;
    	n = re();
    	for (i = 1; i <= n; i++)
    		f[i][i] = re(), r[i][i] = i;
    	for (l = 2; l <= n; l++)
    		for (i = 1; i + l - 1 <= n; i++)
    		{
    			j = i + l - 1;
    			f[i][j] = f[i][i] + f[i + 1][j];
    			r[i][j] = i;
    			for (k = i + 1; k < j; k++)
    				if (f[i][j] < f[i][k - 1] * f[k + 1][j] + f[k][k])
    				{
    					f[i][j] = f[i][k - 1] * f[k + 1][j] + f[k][k];
    					r[i][j] = k;
    				}
    		}
    	printf("%lld
    ", f[1][n]);
    	pr(1, n);
    	return 0;
    }
    
  • 相关阅读:
    【机器学习具体解释】概率生成模型与朴素贝叶斯分类器
    Android中经常使用的bitmap处理方法
    微信第三方平台开发流程
    Java 文章链接
    Axure实现banner功能
    poi实现excel的导入导出功能
    github- 优秀资源总结
    java进阶文章优选链接,面试干货集合
    百万it资源百度网盘链接分享
    MySQL-Access denied for user 'username'@'localhost' (using password: YES) 解决
  • 原文地址:https://www.cnblogs.com/Iowa-Battleship/p/10181755.html
Copyright © 2020-2023  润新知