emmmmmm,第二篇文章,多多写文章,好好掌握知识!


前言

原本在educoder上刷题,刷到[粉刷匠]一题,使用区间DP来做的。自己之前曾经小部分刷过背包DP的题目,对于区间DP还是知之甚少。在稍微了解了区间DP之后,尝试刷题巩固。

这一题来自   Luogu  P2858 [USACO06FEB]Treats for the Cows G/S


一、区间DP

OI WIKI -区间DP

关于动态规划,其实说白了,就是一种递推。当我们解决大问题的时候,先把它 分解 为若干个子问题,再把它 合并 成当前所需的结果。有点类似于递归的感觉,而递归会重复计算,普通dp 与记忆化搜索不会。

而区间dp,就是这类问题中的一小类。在我们的 分解 操作时,它需要取任意区间的子问题结果。这类问题就叫做区间dp。

对于大多数问题,区间dp 的架构像这样:dp(i,j) 被拆分为若干个dp(l,r)​ (其中 i<=l <= r <=j),通过这些小区间计算出来的dp 值推算dp(i,j)​。而dp 的两个下标代表一个区间的左端点与右端点。

通常,我们在做此类问题时,是由小区间推到为大区间。所以,我们要先枚举小区间,再枚举大区间,也就是 枚举长度 。

————引自洛谷BreakPlus' Blog

区间DP经典模板:

memset(dp,0,sizeof(dp))//初始dp数组
for(int len=2;len<=n;++len){//枚举区间长度for(int i=1;i<n;++i){//枚举区间的起点int j=i+len-1;//根据起点和长度得出终点if(j>n) break;//符合条件的终点for(int k=i;k<=j;++k)//枚举最优分割点dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);//状态转移方程}
}
//引自mumei314的博客

记住边界条件是len=1时的情况,从小区间推到大区间,动态转移方程由实际的题意给出。

二、P2858 [USACO06FEB]Treats for the Cows G/S

传送门

1.题目描述

FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving vast amounts of milk. FJ sells one treat per day and wants to maximize the money he receives over a given period time.

The treats are interesting for many reasons:The treats are numbered 1..N and stored sequentially in single file in a long box that is open at both ends. On any day, FJ can retrieve one treat from either end of his stash of treats.Like fine wines and delicious cheeses, the treats improve with age and command greater prices.The treats are not uniform: some are better and have higher intrinsic value. Treat i has value v(i) (1 <= v(i) <= 1000).Cows pay more for treats that have aged longer: a cow will pay v(i)*a for a treat of age a.Given the values v(i) of each of the treats lined up in order of the index i in their box, what is the greatest value FJ can receive for them if he orders their sale optimally?

The first treat is sold on day 1 and has age a=1. Each subsequent day increases the age by 1.

约翰经常给产奶量高的奶牛发特殊津贴,于是很快奶牛们拥有了大笔不知该怎么花的钱.为此,约翰购置了N(1≤N≤2000)份美味的零食来卖给奶牛们.每天约翰售出一份零食.当然约翰希望这些零食全部售出后能得到最大的收益.这些零食有以下这些有趣的特性:

•零食按照1..N编号,它们被排成一列放在一个很长的盒子里.盒子的两端都有开口,约翰每

天可以从盒子的任一端取出最外面的一个.

•与美酒与好吃的奶酪相似,这些零食储存得越久就越好吃.当然,这样约翰就可以把它们卖出更高的价钱.

•每份零食的初始价值不一定相同.约翰进货时,第i份零食的初始价值为Vi(1≤Vi≤1000).

•第i份零食如果在被买进后的第a天出售,则它的售价是vi×a.

Vi的是从盒子顶端往下的第i份零食的初始价值.约翰告诉了你所有零食的初始价值,并希望你能帮他计算一下,在这些零食全被卖出后,他最多能得到多少钱.

2.输入格式

Line 1: A single integer, N

Lines 2..N+1: Line i+1 contains the value of treat v(i)

3.输出格式

Line 1: The maximum revenue FJ can achieve by selling the treats

4.输入输出样例

输入 #1                                                                        输出 #1

5                                                43
1
3
1
5
2

三、算法思考

1.五大三粗从贪心开始。

每次只能从头和尾取出元素,也即每次都只有两个选择——头出、尾出。那么贪心是否能行呢?

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<limits.h>
#include<iomanip>using namespace std;int n;
int v[2005];
int head,tail;
int day=0;
int ans=0;int main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n;head=1;tail=n;for(int i=1;i<=n;++i){cin>>v[i];}while(tail>=head){day++;if(v[head]<v[tail]){ans+=v[head]*day;head++;}else{ans+=v[tail]*day;tail--;}}cout<<ans;return 0;
} 

好嘛,提交27/100分,妥妥的WA了。

我们来看看贪心为什么不可以——什么时候可以用贪心?

贪心算法的适用

贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是局部最优解能决定全局最优解。简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解

算法思想:从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。

贪心算法的适用范围:

贪心算法并不能总求得问题的整体最优解。但对于某些问题,却总能求得整体最优解,这要看问题时什么了。只要能满足贪心算法的两个性质:贪心选择性质和最优子结构性质,贪心算法就可以出色地求出问题的整体最优解。即使某些问题,贪心算法不能求得整体的最优解,贪心算法也能求出大概的整体最优解。如果你的要求不是太高,贪心算法是一个很好的选择。最优子结构性质是比较容易看出来的,但是贪心选择性质就没那么容易了,这个时候需要证明。证明往往使用数学归纳法。(CSDN博主「韦盛江」)

本题不适用贪心

原因就在于本题目的具有后效性。

构造一个简单的例子:13个数据——9 9 9 9 9 9 1 1 1 1 1 1 10

贪心明显得出了错误的答案,具体请读者实操。

2.经典的区间DP

为得到(1,n)整个区间上卖出方案所得到金钱的最大值,可以从区间(2,n)和(1,n-1)得到,同样的以此类推,最终可将方案归到最小长度的区间。我们找到了递归的出口。

——由小区间的最优值得到大区间的最优值,不就是区间DP所能解决的问题吗。

还记得我们上方的区间DP板子吗,O(n^3)的复杂度,内部有一层对断点K的遍历,然而本题已经说明取数只能从头或者尾部选择,这就少了对K的遍历。

根据题义某一区间的最优值来自于len-1的子区间,我们可以写出状态转移方程。

dp[left][right]=max(dp[left+1][right]+v[left]*(n-len+1),dp[left][right-1]+v[right]*(n-len+1));

(emmm个人习惯/癖好,简单来说right,left可用i,j代替。/手动狗头)

AC代码如下:

//区间DP
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<limits.h>
#include<iomanip>
using namespace std;int n,v[2005];
int dp[2005][2005];
//dp[i][j]表示从区间i到j所能得到的局部最优消费值 int main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n;for(int i=1;i<=n;++i){cin>>v[i];dp[i][i]=v[i]*n;//初始化dp } //区间dp板子for(int len=2;len<=n;++len){for(int left=1;left<=n;++left){//i为区间左端点 int right=left+len-1;if(right>n)continue;dp[left][right]=max(dp[left+1][right]+v[left]*(n-len+1),dp[left][right-1]+v[right]*(n-len+1));}}   cout<<dp[1][n];return 0;
} 

三、结语

区间DP的题目只是刚刚接触到,大多都是板子题,需要大量做题,找到适用区间DP以及合理的转移方程。此外,各种优化方法在初步掌握之后,也需要了解熟练运用。

对于这一题,Luogu官网题解,点击这里

P2858 [USACO06FEB]Treats for the Cows G/S 题解相关推荐

  1. [USACO06FEB]Treats for the Cows G/S奶牛零食(区间dp)

    洛谷 acwing #include <bits/stdc++.h> #include <iostream> #include <cstring> #include ...

  2. 动态规划训练20 [Treats for the Cows POJ - 3186 ]

    Treats for the Cows POJ - 3186 简单的区间DP,就不解释了. #include<iostream> #include<cstdio> using ...

  3. Treats for the Cows

    问题描述 Description FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money f ...

  4. P2881 [USACO07MAR]Ranking the Cows G

    P2881 [USACO07MAR]Ranking the Cows G 题目描述 输出格式 Line 1: A single integer that is the minimum value of ...

  5. POJ - 3186 Treats for the Cows DP

    传送门 乍一看与cf的某道题很相似,做了半天的贪心,然后是个二维dp. 这道题难的点在于你无法从最先取的值推到最后取的值,只能从内往外推.如果能看出来这点,其实就不难,但是很难想. 一开始dp[i][ ...

  6. 解题报告:luoguP2868 Sightseeing Cows G(最优比率环,负环判定,二分答案)

    根据题意,我们要环上各点权值之和除以各边权值之和最大. 求最大答案,很明显可以使用二分答案.那么我们假设当前答案为 x,如果有更大的答案,那么方程就可以按下图转换: 也就是说如果有更大的答案,则有一个 ...

  7. poj3186 Treats for the Cows(区间)

    题目链接:http://poj.org/problem?id=3186 题意:第一个数是N,接下来N个数,每次只能从队列的首或者尾取出元素. ans=每次取出的值*出列的序号.求ans的最大值. 样例 ...

  8. BZOJ1652 [Usaco2006 Feb]Treats for the Cows

    蒟蒻许久没做题了,然后连动规方程都写不出了. 参照iwtwiioi大神,这样表示区间貌似更方便. 令f[i, j]表示i到j还没卖出去,则 f[i, j] = max(f[i + 1, j] + v[ ...

  9. POJ 3186 Treats for the Cows dp

    给你n个数   每一次只取一个数   只能前后两个方向取   第i次取出数的价值为自身价值*i   问最大价值为多少 #include<cstdio> #include<cstrin ...

最新文章

  1. Spring Boot 的单元测试和集成测试
  2. ie8下jquery改变PNG的opacity出现黑边,ie6下png透明解决办法
  3. java服务器测试_正确的方法来测试服务器是否在Java中运行?
  4. 【Java TreeMap】测试TreeMap的使用、Comparabe自定义类的自定义排序方式
  5. postgreSql 常用操作总结
  6. 机器学习——深度学习之编程工具、流行网络结构、卷积神经网络结构的应用
  7. Oracle之PLSQL总结
  8. 不同范数下的余弦定理_第06题 | 从源头追溯「余弦定理」amp; 文理科知识点的异同...
  9. ios开发之--令UITableView滚动到指定位置
  10. 生成Treeview树 递归方法
  11. CSC公派|小红本及小黄本的办理
  12. __stdcall调用约定
  13. 关于流浪狗社会现状的调查报告
  14. html中哪些字体不识别中文字体,div字体_正确设置div兼容的汉字中文字体
  15. kafka reassign 限速_简单明了,Kafka与MQ的区别
  16. 软件行业如何开始创业
  17. SLCP验厂辅导,发布网关是SLCP系统中用于数据托管和共享的关键角色
  18. 泰坦尼克号乘客生存情况预测分析之第三部分建模及模型评价
  19. NanoHttpd Demo是个好东西
  20. python中open()函数里中文处理

热门文章

  1. 基于51单片机的羽毛球计分器proteus仿真程序设计
  2. 隐函数+导数定义思路
  3. 【算法之美-经典问题】九宫格问题
  4. ubuntu系统(十):卸载Ubuntu系统详细步骤
  5. AFLW2000-3D数据库介绍及自带代码使用
  6. Vue2.0学习笔记二 基础语法
  7. Node.js +个人博客系统搭建设计方案
  8. The most stupid C bug ever
  9. windows上ssh-keygen.exe 用法
  10. MySQL单表操作约束