区间DP

来源:互联网 发布:淘宝会员注册登录 编辑:程序博客网 时间:2024/04/29 11:31

先来看看题吧.

1382 沙子合并

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 大师 Master

题目描述 Description

   设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300)。每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为 1 3 5 2 我们可以先合并1、2堆,代价为4,得到4 5 2 又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总的代价最小。输出最小代价。

输入描述 Input Description

第一行一个数N表示沙子的堆数N。
第二行N个数,表示每堆沙子的质量。 <=1000

输出描述 Output Description

合并的最小代价

样例输入 Sample Input

4
1 3 5 2

样例输出 Sample Output

22

题解:
#include<iostream>#define inf 10e6using namespace std;int sum[310],f[310][310];int min(int a,int b){return a>b?b:a;}int dp(int l,int r){int k;if(l==r) return 0;for(k=l;k<r;k++){if(f[l][k]==inf) f[l][k]=dp(l,k);if(f[k+1][r]==inf) f[k+1][r]=dp(k+1,r);f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+sum[r]-sum[l-1]); }return f[l][r];}int main(){int n,t;cin>>n;for(int i=0;i<310;i++) for(int j=0;j<310;j++) f[i][j]=inf;  for(int i=1;i<=n;i++){cin>>t;sum[i]+=sum[i-1]+t;f[i][i]=0;}cout<<dp(1,n)<<endl;return 0;}
<span style="box-sizing: border-box; color: rgb(88, 102, 110); font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, 微软雅黑, 黑体, sans-serif; font-size: 24px; line-height: 26.4px; background-color: rgb(240, 243, 244);">2192 删数</span>
题目描述 Description

有N个不同的正整数数x1, x2, ... xN 排成一排,我们可以从左边或右边去掉连续的i个数(只能从两边删除数),1<=i<=n,剩下N-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。
每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|xi – xk|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。
任务
如何操作可以得到最大值,求操作的最大价值。

输入描述 Input Description

输入文件remove.in 的第一行为一个正整数N,第二行有N个用空格隔开的N个不同的正整数。
N个操作数为1..1000 之间的整数。

输出描述 Output Description

输出文件remove.out 包含一个正整数,为操作的最大值

样例输入 Sample Input

6
54 29 196 21 133 118

样例输出 Sample Output

768

数据范围及提示 Data Size & Hint

3<=N<=100

#include<iostream>using namespace std;int f[200][200],a[200];char s[100000000000]; int max(int a,int b){return a>b?a:b;}int abs(int x){return x>0?x:-x;}int dp(int l,int r){int x=-100;if(f[l][r]) return f[l][r];if(l==r) return a[l];if(l>r) return 0;for(int i=0;i<2;i++)  for(int j=2;j<=r-l+1;j++)  {          if(i==0)   x=max(x,j*abs(a[l+j-1]-a[l])+dp(l+j,r));          else if(i==1)   x=max(x,j*abs(a[r-j+1]-a[r])+dp(l,r-j));  }x=max(x,a[l]+dp(l+1,r));x=max(x,a[r]+dp(l,r-1));f[l][r]=x;return f[l][r]; }int main(){int n;cin>>n;for(int i=1;i<=n;i++) cin>>a[i];cout<<dp(1,n)<<endl;return 0;}
<span style="box-sizing: border-box; color: rgb(88, 102, 110); font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, 微软雅黑, 黑体, sans-serif; font-size: 24px; line-height: 26.4px; background-color: rgb(240, 243, 244);">1090 加分二叉树</span>

题目描述 Description

设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为ditree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:

subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数

若某个子树为主,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空

子树。

试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;

1tree的最高加分

2tree的前序遍历

 

 

现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。

输入描述 Input Description

1行:一个整数nn<=30),为节点个数。

2行:n个用空格隔开的整数,为每个节点的分数(分数<=100

输出描述 Output Description

1行:一个整数,为最高加分(结果不会超过4,000,000,000)。

2行:n个用空格隔开的整数,为该树的前序遍历。

样例输入 Sample Input

5

5 7 1 2 10

样例输出 Sample Output

145

3 1 2 4 5

数据范围及提示 Data Size & Hint

nn<=30)

分数<=100

#include<iostream>using namespace std;int a[50],f[50][50],g[50][50];int dp(int l,int r){    int t;if(l>r) return 1;if(l==r) return a[l];if(f[l][r]) return f[l][r];for(int k=l;k<=r;k++){t=dp(l,k-1)*dp(k+1,r)+a[k];if(t>f[l][r]){f[l][r]=t;g[l][r]=k;}}return f[l][r];}void print(int a,int b){if(a>b) return;    if(a==b){cout<<a<<" ";return;}cout<<g[a][b]<<" ";print(a,g[a][b]-1);print(g[a][b]+1,b);}int main(){int n;cin>>n;for(int i=1;i<=n;i++) cin>>a[i];cout<<dp(1,n)<<endl;print(1,n);return 0;}

然后就可以看出区间DP的一般套路:

DP(l,r)
{
  判断边界(l>r or l=r or f[l][r]!=0)
  枚举k值,划分中间状态
  {
      if(f[l][k]...) f[l][k]=DP(l,k);
      if(f[k+1][r]...) f[k+1][r]=DP(k+1,r);
      f[l][r]=min or max(f[l][r],f[l][k]...f[k+1][r])此处视具体题目要求
    }
    return f[l][r];
}
main
{
   读取数据;
   cout<<DP(1,n)
}
//以上为区间DP的一般套路,如果题目有其他特殊要求应适度变化,如删数:
for 枚举两种操作
           for 枚举k值,划分中间状态





0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝支付宝里没钱了买家退款怎么办 如果外包把员工社保忘交了怎么办 外包工人没有和包工头的证据怎么办 试用期辞职公司给交的社保怎么办 单位给交员工不想交社保怎么办 淘宝收不到卖家的信息怎么办 不小心把微信聊天记录删掉了怎么办 不小心把打印机驱动删除了怎么办 蓝牙不小心点到忽略此设备怎么办 千牛工作台无线开店确认不了怎么办 开通诚信通后营业执照注销了怎么办 淘宝标的货跟发的不一样怎么办 wps表格里单元之间重叠了怎么办 淘宝店铺停了一段时间没了怎么办 转转买家收货为敲诈卖家怎么办 淘宝被投诉盗用官网图片怎么办 淘宝订单买下后卖家告知无货怎么办 盗图被删除还是待处理违规该怎么办 如果买家说你们的买家秀一样怎么办 花呗唤起安全核身验证失败怎么办 淘宝买东西花呗分期额度不够怎么办 支付宝余额支付额度已达上限怎么办 我是淘宝卖家遇到无良买家怎么办 我的保证金被淘宝当做违约金怎么办 淘宝顾客不想退货申请仅退款怎么办 被买家提供证明说我卖假货怎么办 淘宝退货快递公司填错了俩次怎么办 淘宝上退货把运单号写错了怎么办? 阿里巴巴发货了快递单号掉了怎么办 淘宝上买东西货物被物流扣留怎么办 淘宝买错了对方已发货怎么办 淘宝卖家发货的时候没货了怎么办 买了球显示未出票中奖了怎么办 点错了允许易企秀获得权限怎么办 淘宝还没发货商家拒绝退款怎么办 买家不补邮费还要你发货怎么办 天猫客服提示获取信息失败怎么办 拼多多下单了商家不发货怎么办 店铺扣2分宝贝降权了怎么办 淘宝店没订单没流量怎么办啊 淘宝id账号登录密码忘记了怎么办