区间dp

区间dp就是在区间上的动态规划,求解一段区间上的最优解,通过合并小区间的最优解来得到整个大区间上的最优解的算法。
区间dp一般都是三层for循环 需要注意的是 区间是从小到大 因为dp是后一个用到前一个的给出的结果 并进行递推 
区间dp常用的一个状态就是dp[i][j]表示i~j这个区间的最优解多少
区间dp的大致思路:
  1.确定状态 初始化长度为 n 的dp[][]的值
  2.枚举区间长度 枚举区间的起始点 (有些题还需枚举断点) 由小区间转移到大区间
  3.最终答案基本是 dp[1][n] or dp[0][n-1]

 

区间dp 模板
 1 //memset(dp,0,sizeof(dp)) 初始化DP数组
 2 for(int i=1;i<=n;i++){
 3     dp[i][i]=初始值
 4 }
 5 for(int len=2;len<=n;len++)  //区间长度
 6 for(int i=1;i<=n;i++){       //枚举区间起点
 7     int j=i+len-1;           //区间终点
 8     if(j>n) break;           //越界结束
 9     for(int k=i;k<j;k++){     //枚举分割点,构造状态转移方程
10         dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
11     }
12 }

 



 

升级

1.由直线型变换成环形
  若是环形,则需要将整个数组复制一遍,然后在统计答案的时候,把1-n开头长度为n的区间求一个min 即可

2.优化 —— 四边形不等式优化

https://blog.csdn.net/noiau/article/details/72514812
//大佬blog 侵删


 

题目

1.石子合并

2.Pangu and stone
 1 #include<iostream>
 2 #include<cstring>
 3 
 4 using namespace std;
 5 const int inf=0x3f3f3f3f;
 6 int n,l,r,a[105],sum[105],dp[105][105][105];
 7 
 8 void f(){
 9     for(int d=1;d<=n;d++){            //区间长度 
10         for(int i=1;i+d-1<=n;i++){            //区间起点 
11             int j=i+d-1;                    //区间终点 
12             for(int k=i;k<j;k++){            //在区间内枚举 
13                 for(int s=l;s<=r;s++){            //一次 可 合并 区间 数 
14                     dp[i][j][1]=min(dp[i][j][1],dp[i][k][s-1]+dp[k+1][j][1]+sum[j]-sum[i-1]);
15                 }
16             }
17             for(int k=2;k<=n;k++){
18                 for(int s=i;s<j;s++){            //枚举分割点 构造状态转移方程 
19                     dp[i][j][k]=min(dp[i][j][k],dp[i][s][k-1]+dp[s+1][j][1]);
20                 }
21             }
22         }
23     } 
24     if(dp[1][n][1]==inf)cout<<0<<endl;
25     else cout<<dp[1][n][1]<<endl;    
26 } 
27 
28 int main(){
29     while(cin>>n>>l>>r){
30         for(int i=1;i<=n;i++){
31             cin>>a[i];
32             sum[i]=sum[i-1]+a[i];
33         }
34         memset(dp,inf,sizeof(dp));
35         for(int i=1;i<=n;i++){
36             for(int j=i;j<=n;j++)
37                 dp[i][j][j-i+1]=0;
38         }
39         f();
40     }
41     return 0;
42 }
View Code

 







 

转载于:https://www.cnblogs.com/jjjjjjy/p/11367525.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值