HDU4571-区间DP,记忆化搜索,递推
来源:互联网 发布:c++ gui qt 4编程 编辑:程序博客网 时间:2024/05/16 02:20
F
给定一个数组,把这个数组分成n段,
每一份的值为 第一个数 a*pow(2,i),i为段的长度。
用记忆化搜索
dp[i]=min(dp[i],dp[x]+a[i]*1<<(x-i))
x-i为i为头的段的长度,首为i,尾为x-1;
x为新段的长度。
方法1 记忆话搜索
这个最好理解了,但是最重要的是对x的控制。
和边界的处理。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;typedef long long ll;const int maxn=70;ll dp[maxn];ll a[maxn];int n;int t;int dfs(int x){ if(x>n) return 0; if(dp[x]!=-1) return dp[x]; dp[x]=1e19; /*i是下一段的初始值。 进行当前合法段的搜索 1 长度不得超过20,i+19正好就是20; 2 长度不得过n。 */ for(int i=x+1;i<=min(x+20,n+1);i++) { dp[x]=min(dp[x],dfs(i)+a[x]*(1<<i-x)); } //cout<<dp[x]<<endl; return dp[x];}int main(){ scanf("%d",&t); while(t--) { scanf("%d",&n); memset(dp,-1,sizeof(dp)); ll sum=0; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); sum+=a[i]*2; } ll sum1=dfs(1); ll ans=min(sum1,sum); cout<<ans<<endl; } return 0;}
方法2 区间dp,二维的也好理解。
类似的 松弛操作的区间dp的典型操作。。
#include <iostream>#include <cstdio>#include <cstdlib>using namespace std;/*给定你一个数组,分为若干份,每份大小不得大于20要求是 每一份最大不能超过20;方法1 dp[i][j]为i到j(不包括j)这个区间的最大值。dp[i][j]=dp[i][k]+dp[i][k+1][j]k作为一个分段,当前的dp保存的是上一个区间的大小。要注意初始化。1712445432 10000 10000 10000 10000 10000 1000010000 4 10000 10000 10000 10000 1000010000 10000 8 10000 10000 10000 1000010000 10000 10000 8 10000 10000 1000010000 10000 10000 10000 10 10000 1000010000 10000 10000 10000 10000 8 1000010000 10000 10000 10000 10000 10000 6*************2 4 10000 10000 10000 10000 1000010000 4 8 10000 10000 10000 1000010000 10000 8 16 10000 10000 1000010000 10000 10000 8 16 10000 1000010000 10000 10000 10000 10 18 1000010000 10000 10000 10000 10000 8 1410000 10000 10000 10000 10000 10000 6*************2 4 8 10000 10000 10000 1000010000 4 8 16 10000 10000 1000010000 10000 8 16 24 10000 1000010000 10000 10000 8 16 24 1000010000 10000 10000 10000 10 18 2410000 10000 10000 10000 10000 8 1410000 10000 10000 10000 10000 10000 6*************2 4 8 16 10000 10000 1000010000 4 8 16 24 10000 1000010000 10000 8 16 24 32 1000010000 10000 10000 8 16 24 3010000 10000 10000 10000 10 18 2410000 10000 10000 10000 10000 8 1410000 10000 10000 10000 10000 10000 6*************2 4 8 16 24 10000 1000010000 4 8 16 24 32 1000010000 10000 8 16 24 32 3810000 10000 10000 8 16 24 3010000 10000 10000 10000 10 18 2410000 10000 10000 10000 10000 8 1410000 10000 10000 10000 10000 10000 6*************2 4 8 16 24 32 1000010000 4 8 16 24 32 3810000 10000 8 16 24 32 3810000 10000 10000 8 16 24 3010000 10000 10000 10000 10 18 2410000 10000 10000 10000 10000 8 1410000 10000 10000 10000 10000 10000 6*************2 4 8 16 24 32 3810000 4 8 16 24 32 3810000 10000 8 16 24 32 3810000 10000 10000 8 16 24 3010000 10000 10000 10000 10 18 2410000 10000 10000 10000 10000 8 1410000 10000 10000 10000 10000 10000 6*************38*/const int maxn=2000;typedef long long ll;ll dp[maxn][maxn];ll a[maxn];int t;int m;int main(){ ios::sync_with_stdio(false); cin>>t; while(t--) { cin>>m; for(int i=1;i<=m;i++) cin>>a[i]; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) dp[i][j]=1e19; for(int i=0;i<m;i++) { for(int j=1;j<=m-i;j++) { if(i<20) dp[j][j+i]=a[j]*(1<<i+1); for(int k=j;k<j+i;k++) dp[j][j+i]=min(dp[j][k]+dp[k+1][j+i],dp[j][j+i]); } /*for(int xx=1;xx<=m;xx++) {for(int yy=1;yy<=m;yy++) cout<<dp[xx][yy]<<" "; cout<<endl; } cout<<"*************"<<endl;*/ } //cout<<dp[1][5]<<endl; //cout<<dp[5][7]<<endl; cout<<dp[1][m]<<endl; } return 0;}
3 递推,递推的方法和第四个不一样。
dp[i]为从1到i的最优解,
要知道,当为j时,最后一段首尾 i-j+1.
#include <iostream>#include <cstdio>#include <cstdlib>using namespace std;typedef long long ll;ll dp[70];ll a[70];int main(){ int t; int n; cin>>t; while(t--) { cin>>n; long long sum=0; for(int i=1;i<=n;i++) {cin>>a[i]; sum+=a[i]*2; } for(int i=1;i<=n;i++) { dp[i]=1e19; for(int j=1;j<=i;j++) { if(j>20)break; dp[i]=min(dp[i-j]+a[i-j+1]*(1ll<<j),dp[i]); } } ll ans=min(sum,dp[n]); cout<<ans<<endl; } return 0;}
4 这个和 记忆化搜索几乎一模一样。
记忆化搜索也有dp[n]的处理,只不过在递归的过程中自己执行了。
#include<iostream>#include<cstdio>#include<list>#include<algorithm>#include<cstring>#include<string>#include<queue>#include<stack>#include<map>#include<vector>#include<cmath>#include<memory.h>#include<set>#define ll long long#define eps 1e-8#define inf 0xfffffffconst ll INF = 1ll<<61;using namespace std;//vector<pair<int,int> > G;//typedef pair<int,int > P;//vector<pair<int,int> > ::iterator iter;////map<ll,int >mp;//map<ll,int >::iterator p;ll num[100 + 56];ll dp[100 + 56];void init() { memset(num,0,sizeof(num)); memset(dp,0,sizeof(dp));}int main() { int t; scanf("%d",&t); while(t--) { init(); int n; scanf("%d",&n); ll ans = 0ll; for(int i=1;i<=n;i++) { scanf("%I64d",#[i]); ans += 2 * num[i];//分n段 } dp[n] = 2 * num[n]; for(int i=n-1;i>0;i--) { dp[i] = INF; for(int j=i+1;j<=n+1;j++) { if(j > i + 20)break; dp[i] = min(dp[i],dp[j] + num[i] * (1ll<<j - i)); } } printf("%I64d\n",min(ans,dp[1])); } return 0;}
阅读全文
0 0
- HDU4571-区间DP,记忆化搜索,递推
- HDU4571 记忆化搜索
- hdu2476String painter【区间dp】递推+递归的记忆化搜索
- hdu4283 You Are the One 区间dp 记忆化搜索or递推
- hdu4571最短路+记忆化搜索
- POJ1088 滑雪 经典DP 记忆化搜索和递推
- HDU3427 Clickomania【记忆化搜索】【区间DP】
- 记忆化搜索求解区间型dp
- poj1390区间dp+记忆化搜索
- 记忆化搜索 区间dp uva629
- [CDOJ1321]-区间DP(记忆化搜索)
- hdu4283区间dp 记忆化搜索 区间分化
- 记忆化搜索与递推
- 区间DP(可以看成记忆化搜索)
- Uva 10891 Game of Sum - 区间DP..记忆化搜索
- uva 10453 - Make Palindrome (区间dp,记忆化搜索)
- UVA1351-----String Compression-----区间DP(记忆化搜索实现)
- 149D - Coloring Brackets(区间DP 记忆化搜索)
- 数据库编程
- Android直播
- “玲珑杯”线上赛 Round #15 河南专场:G -- 咸鱼拷问
- 用vs2010打开版本较高vs的sln
- NAMENODE工作机制,元数据管理(元数据存储机制、元数据手动查看)、元数据的checkpoint、元数据目录说明(来自学习资料)
- HDU4571-区间DP,记忆化搜索,递推
- Vscode DOS和UNIX脚本文件之间相互转换的多种方法
- 第1周-Python基础
- 陈纪修老师《数学分析》 第05章:微分中值定理及其应用 笔记
- AS报错:Installation failed with message Failed to establish session
- 无限轮播之网络图片
- ffmpeg用到的命令
- 使用caffe时如何生成和使用日志(log)文件
- IDEA Junit4配置