加分二叉树 noip
来源:互联网 发布:unity编程 编辑:程序博客网 时间:2024/05/20 18:42
首先这肯定不是标解
树形四维dp
程序好理解,就是以 x为root,左子树的范围或右子书的范围,0 1判断
求前序费了不少劲,最后只得待退回去,一开始wa了一个点,是一个很隐蔽的地方,
if (s1==1&&s2==1&&(l>i-1&&i+1>r))
s=a[i];
(l>i-1&&i+1>r)这个special judge 没有,导致的
#include<iostream>using namespace std;long long f[31][31][31][2];int a[101];int scl(int root,int l,int r,int p){ int ans=0;int i; for (i=l;i<=r;++i) { long long s1=f[i][l][i-1][0]; long long s2=f[i][i+1][r][1]; long long s=s1*s2+a[i]; if (s1==1&&s2==1&&(l>i-1&&i+1>r)) s=a[i]; if (s==f[root][l][r][p]) break; } cout<<i<<" "; if (l<=i-1) scl(i,l,i-1,0); if (i+1<=r) scl(i,i+1,r,1);}int dp(int x,int l,int r,int p){ if (p==0&&r<l) return 1; if (p&&l>r) return 1; if (f[x][l][r][p]) return f[x][l][r][p]; else { for (int i=l;i<=r;++i) { f[i][l][i-1][0]=dp(i,l,i-1,0); f[i][i+1][r][1]=dp(i,i+1,r,1); long long s=f[i][l][i-1][0]*f[i][i+1][r][1]+a[i]; if (f[i][i+1][r][1]==1&&f[i][l][i-1][0]==1) s=a[i]; if (s>f[x][l][r][p]) { f[x][l][r][p]=s; } } } return f[x][l][r][p];}int main(){ int n;cin>>n; for (int i=1;i<=n;++i) cin>>a[i]; long long ans=0; int root; for (int i=1;i<=n;++i) { long long s1=dp(i,1,i-1,0); long long s2=dp(i,i+1,n,1); long long s=s1*s2+a[i]; if (s>ans) root=i; ans=max(s,ans); } cout<<ans<<endl; cout<<root<<" "; scl(root,1,root-1,0); scl(root,root+1,n,1);}
看一下正解吧
【任务一】采用动态规划方法计算最大分值本题可以采用动态规划方法来解决,具体如下:设f[i, j]为顶点i . . 顶点j所组成的子树的最大分值。若f[i, j] = -1,则表明最大分值尚未计算出。f(i,j)={1 (i>j) ; 顶点i的分数 (i=j) ; max(f{i,k-1}*f{k+1,j}+顶点i的分数 (i<j) 『k取i~j』)root[i, j]——顶点i..顶点j所组成的子树达到最大分值时的根编号。当i = j时,root[i, i] := i。由于问题没有明显的阶段特征,而是呈现为非线性的树形结构,因此,我们采用后序遍历的顺序来计算状态转移方程。计算过程如下:long long search(int L, int r) // 递归计算f[L][r]{int k;long long now, ans; // 当前分值if (L > r) return 1;if (f[L][r]== -1) // 若尚未计算出顶点L..顶点r对应子树的最高分值 for(k=L; k<=r; k++) { // 穷举每一个可能的子根k now = search(L, k-1) * search(k+1, r) + f[k][k]; // 计算以k为根的子树的分值 if(now > f[L][r]) {//若该分值为目前最高,则记入状态转移方程,并记下子根} f[L][r] = now; root[L][r] = k; }}return f[L][r]; {返回顶点L..顶点r对应子树的最高分值}}void preorder(int L, int r){if (L > r) return;if (firstwrite)firstwrite = false;else cout<<‘ ‘; // 顶点间用空格分开cout << root[L][r]; // 输出子树的根preorder(L, root[L][r]-1); // 前序遍历左子树preorder(root[L][r]+1, r); // 前序遍历右子树}
2 1
- 加分二叉树 noip
- NOIP 2003 加分二叉树
- NOIP 2003 加分二叉树
- Noip 2003 加分二叉树
- Noip 2003 加分二叉树
- Noip 2003T3 加分二叉树
- [NOIP 2003] 加分二叉树:DP
- [NOIP提高组2003]加分二叉树
- 加分二叉树 2003年NOIP全国联赛提高组
- 加分二叉树 2003年NOIP全国联赛提高组
- 加分二叉树[NOIP 2003提高组][Codevs 1090]
- 「2003NOIP提高组」加分二叉树
- NOIP 2003 提高组 复赛 加分二叉树
- 加分二叉树
- 1078 加分二叉树
- 加分二叉树_DP
- 加分二叉树
- 二叉树--面试加分
- opencv3.0 均值 标准差 函数 mean meanStdDev
- 数据库表的操作
- awk与sed 合并多行为一行
- Labview2016安装及破解步骤
- 做好职业规划很重要
- 加分二叉树 noip
- 工作学习系列之:spring学习-第一篇
- 最小生成树
- LoRa开发5:发送随机数据
- Android自定义控件——组合控件
- 职场中如何做到加薪
- 数据结构(四)——队列(C语言实现)
- String,StringBuilder和StringBuffer的区别
- ES6 + Webpack + React + Babel 如何在低版本浏览器上愉快的玩耍(下)