TYVJ P1078 删数 Label:区间dp
描述
每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|xi – xk|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。
任务
如何操作可以得到最大值,求操作的最大价值。
输入格式
3<=N<=100,N个操作数为1..1000 之间的整数。
输出格式
测试样例1
输入
6
54 29 196 21 133 118
输出
768
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[],f[][],sum[][];
int N; int get_sum(int l,int r){
if(sum[l][r]>=) return sum[l][r];
else{
int pos=;
pos=abs(a[l]-a[r])*(r-l+);
return pos;
}
} int dp(int l,int r){
if(l==r) return a[l];
if(l+==r){
int pos=;
pos=get_sum(l,r);
pos=max(pos,a[l]+a[r]);
return pos;
}
if(f[l][r]>=) return f[l][r];
for(int k=l+;k<r;k++){//错误代码
f[l][r]=max(f[l][r],dp(l,k) + dp(k+,r));
f[l][r]=max(f[l][r],dp(l,k) + get_sum(k+,r));
f[l][r]=max(f[l][r],get_sum(l,k) + dp(k+,r));
f[l][r]=max(f[l][r],get_sum(l,k) + get_sum(k+,r));
}
return f[l][r];
} int main(){
// freopen("01.txt","r",stdin);
memset(f,-,sizeof(f));
memset(sum,-,sizeof(sum));
scanf("%d",&N);
for(int i=;i<=N;i++) scanf("%d",&a[i]);
printf("%d\n",dp(,N));
return ;
}这个代码没有AC,不知道问题何在,有个点没有过。。。(下文已解决)
我的想法是不管怎么取,所在区域与第几次取是没有关系的。
于是就4种情况。。。//这句话就留着吧,以后明白自己错在哪里
数据如下:
输入
100
169 36 193 11 80 329 155 421 67 222 106 225 175 100 151 227 117 340 129 19 395 292 308 48 89 310 518 302 460 105 355 33 554 455 233 44 293 6 295 7 161 164 556 435 71 402 221 353 203 311 324 217 520 511 108 26 373 13 95 241 230 162 403 258 365 20 326 8 218 176 206 516 120 351 275 157 350 103 330 204 90 187 451 167 104 418 541 215 349 214 294 426 216 212 420 111 121 424 283 22输出
51206
补充
找到错误了:上述代码没有考虑只有右边取一个的情况,只要把dp条件中k=l+1改为k=l就可以
这个错误犯了好几次了,刚才思考了一下,应该是这个问题,于是过了
附代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[],f[][],sum[][];
int N; int get_sum(int l,int r){
if(sum[l][r]>=) return sum[l][r];
else{
int pos=;
pos=abs(a[l]-a[r])*(r-l+);
return pos;
}
} int dp(int l,int r){
if(l==r) return a[l];
if(l+==r){
int pos=;
pos=get_sum(l,r);
pos=max(pos,a[l]+a[r]);
return pos;
}
if(f[l][r]>=) return f[l][r];
for(int k=l;k<r;k++){//这里被修改了
f[l][r]=max(f[l][r],dp(l,k) + dp(k+,r));
f[l][r]=max(f[l][r],dp(l,k) + get_sum(k+,r));
f[l][r]=max(f[l][r],get_sum(l,k) + dp(k+,r));
f[l][r]=max(f[l][r],get_sum(l,k) + get_sum(k+,r));
}
return f[l][r];
} int main(){
// freopen("01.txt","r",stdin);
memset(f,-,sizeof(f));
memset(sum,-,sizeof(sum));
scanf("%d",&N);
for(int i=;i<=N;i++) scanf("%d",&a[i]);
printf("%d\n",dp(,N));
return ;
}
再补充更优代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int sum[][],f[][],a[],N;
int get_sum(int l,int r){
if(sum[l][r]>=) return sum[l][r];
if(l==r) return sum[l][r]=a[l];
else return sum[l][r]=abs(a[l]-a[r])*(r-l+);
} int dp(int l,int r){
if(f[l][r]>=) return f[l][r];
f[l][r]=get_sum(l,r);//最开始也类似这样的思路,但是没写这句话,
//导致没有考虑到一次全删的情况
for(int k=l;k<r;k++){
f[l][r]=max(f[l][r], get_sum(l,k) + dp(k+,r));
f[l][r]=max(f[l][r], dp(l,k) +get_sum(k+,r));
}
return f[l][r];
} int main(){
// freopen("01.txt","r",stdin);
memset(f,-,sizeof(f));
memset(sum,-,sizeof(sum)); scanf("%d",&N);
for(int i=;i<=N;i++) scanf("%d",&a[i]); printf("%d\n",dp(,N));
return ;
}片段一:
f[l][r]=max(f[l][r],dp(l,k) + dp(k+,r));
f[l][r]=max(f[l][r],dp(l,k) + get_sum(k+,r));
f[l][r]=max(f[l][r],get_sum(l,k) + dp(k+,r));
f[l][r]=max(f[l][r],get_sum(l,k) + get_sum(k+,r));讲一下存在的问题:
1)dp开始时应该对该状态进行初始化,比如补充代码第十六行(片段二)
片段二:
f[l][r]=get_sum(l,r);//最开始也类似这样的思路,但是没写这句话,
//导致没有考虑到一次全删的情况2)片段一第一行代码无用,本来就会考虑到
3)第四行基本上就等同于片段二 ,还绕了个弯
总结起来就是dp应该理解自己要递归什么,然后写完不急调样例,
在脑海中过一遍代码历程,检查是否有状态没有考虑到
再讲一句:sum数组有开45ms,没开60ms
但是如果f数组没开的话就呵呵了
TYVJ P1078 删数 Label:区间dp的更多相关文章
- TYVJ 矩阵取数 Label:高精度+dp
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
- tyvj 1198 矩阵连乘——区间dp
tyvj 1198 矩阵连乘 题目描述 一个n*m矩阵由n行m列共n*m个数排列而成.两个矩阵A和B可以相乘当且仅当A的列数等于B的行数.一个N*M的矩阵乘以一个M*P的矩阵等于一个N*P的矩阵,运算 ...
- Vijos 1451 圆环取数 【区间DP】
背景 小K攒足了路费来到了教主所在的宫殿门前,但是当小K要进去的时候,却发现了要与教主守护者进行一个特殊的游戏,只有取到了最大值才能进去Orz教主…… 描述 守护者拿出被划分为n个格子的一个圆环,每个 ...
- P1005 矩阵取数游戏[区间dp]
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的\(m*n\)的矩阵,矩阵中的每个元素\(a_{i,j}\)均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.经过m次后 ...
- TYVJ P1047 乘积最大 Label:dp
背景 NOIP 2000 普及组 第三道 描述 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力 ...
- 1166 矩阵取数游戏[区间dp+高精度]
1166 矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description [ ...
- TYVJ P1075 硬币游戏 Label:dp
背景 农民John的牛喜欢玩硬币,所以John就为它们发明了一个新的两人硬币游戏,叫做Xoinc. 描述 最初地面上有一堆n个硬币(5<=n<=2000),从上面数第i个硬币的价值为C_i ...
- P1005 矩阵取数游戏 区间dp 高精度
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n \times mn×m的矩阵,矩阵中的每个元素a_{i,j}ai,j均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n ...
- 「LuoguP1430」 序列取数(区间dp
题目描述 给定一个长为n的整数序列(n<=1000),由A和B轮流取数(A先取).每个人可从序列的左端或右端取若干个数(至少一个),但不能两端都取.所有数都被取走后,两人分别统计所取数的和作为各 ...
随机推荐
- 技术分享:WIFI钓鱼的入门姿势
简介 该实验先是搭建一个测试环境,然后创建一个假的无线接入点,把网络连接连接到假的接入点并且强迫用户连接假的无线点. 事先准备 1.无线网卡:无线网卡用于数据包的嗅探和注入. 2. Backtrack ...
- 友盟消息推送和更新XML配置
<receiver android:name="com.umeng.message.NotificationProxyBroadcastReceiver" android:e ...
- 什么是响应式Web设计?怎样进行?
http://beforweb.com/node/6/page/0/3 开始第一篇.老规矩,先无聊的谈论天气一类的话题.十一长假,天气也终于开始有些秋天的味道,坐在屋里甚至觉得需要热咖啡.话说两年前也 ...
- ubuntu 15 安装Qt
Linux 下安装 QT5.4.0 http://blog.163.com/xd8171@126/blog/static/620810432015027111314471/ Linux qt ...
- 44. log(n)求a的n次方[power(a,n)]
[题目] 实现函数double Power(double base, int exponent),求base的exponent次方,不需要考虑溢出. [分析] 这是一道看起来很简单的问题,很容易写出如 ...
- 更改Apache默认网站根目录
Apache服务器网站根目录配置是个比较基本的操作,之前经常用,现在记一下笔记 打开Apache的配置文件,一般在Apache安装目录下的conf/httpd.conf配置文件中修改, 找到 Docu ...
- windows下安装Appserv等php套件之后无法进入数据库管理的问题
在win7下安装Wamp或者Appserv后无法进入数据库管理,但是php.Apache运行全都没问题,mysql可以在命令行中管理,但是就是无法打开phpmyadmin数据库管理,点击后浏览器就显示 ...
- 【JAVA、C++】LeetCode 018 4Sum
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...
- codeforces A. Flipping Game 解题报告
题目链接:http://codeforces.com/problemset/problem/327/A 题意是输入一个只有0和1的序列,要求找出一个合理的区间,在这个区间里面把0变成1,1变成0,使得 ...
- 自定义viewgroup实现ArcMenu
最终效果如下 实现思路 通过效果图,会有几个问题: a.动画效果如何实现 可以看出动画是从顶点外外发射的,可能有人说,那还不简单,默认元素都在定点位置,然后TraslateAnimation就好了:这 ...