dp进阶——饥饿的奶牛
饥饿的奶牛oj上n只有1000,过于水,O(n^2)的算法很容易水过,洛谷上这是一道提高加的题,很难啊,所以要好好拿来练习今天写博客再次复习一下,oi最怕遗忘了。

这道题呢实质是一个区间覆盖的dp,首先是设f[i]表示前i个草地所能获得的最大值,这也就很简单的找到了状态转移方程。
如果当前的前j草地和第i草地不相交f[i]=max(f[i],f[j]+s[i].y-s[i]. x+1);最后所要找的就是max(f[i]);这样一道很简单复杂度为O(n^2)的算法被打出来了。
必须要排序因为在进行判断两个区间是否相交的时候直接用s[i].x>s[i].y,排序的目的很显然是为了让每个判断都能把已判断过的边也直接判断出来,要不有可能一些状态是不合法的转移,这样判断就可以是两个区间或和其他已经累加上的区间是否相交了。
#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
int n,ans=,f[maxn];
struct bwy
{
int x,y;
}s[maxn];
int wy(bwy x,bwy y)//闻道玉门犹被遮,应将性命逐轻车
{
if(x.x==y.x)return x.y<y.y;
return x.x<y.x;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();
memset(f,,sizeof(f));
for(int i=;i<=n;i++)
s[i].x=read(),s[i].y=read();
sort(s+,s++n,wy);
for(int i=;i<=n;i++)
{
for(int j=;j<i;j++)
if(s[j].y<s[i].x)f[i]=max(f[i],f[j]+s[i].y-s[i].x+);
}
for(int i=;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
return ;
}
这个代码a掉oj上的这道题完全没问题了,洛谷上就TLE了,正常现象。于是考虑到算法的优化。
因为f[i]表示的是第i个草堆所能得到的最大值所以f[i]>=f[j],这就满足了一个单调性,我可以通过去找离当前的f[i]最近的f[j]且不和f[i]这个区间相交来进行不必要再次循环一遍从0到i来更新最优解,这就是策略,至于咋么找那就是二分了快速查找,二分查找找出这个j值从而进行对i的更新。
和chty学长的一番交流发现自己排序错了,因为在查找的时候是要保证f[j].y<f[i].x.所以假如是全部靠左端点排序的话你的mid值后面的区间是可能仅仅是左端点是小于当前的但是呢其他点的右端点很可能就将其全部涵盖所以你判断当前的点的右端点是出现问题的,这就保证不了两个区间是不相交的了。于是采用右端点排序使右端点递增就可以保证其他的点也小于当前的点的左端点了。
所以应该讲右端点排序然后比的时候是f[j].y<f[i].x这样的话之前的右端点就可以全部小于当前的左端点了,不会有上方情况的发生。右端点排序后dp的时候就可以继承i-1的最优解了因为后面的点不可能和最优解相交且和不优解相交,这样就可以保证啦。。。想了好久的问题终于因为这一个排序所解决。
下面是代码二分专属:
#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
struct bwy
{
int x,y;
}s[maxn];
int wy(bwy x,bwy y)//闻道玉门犹被遮,应将性命逐轻车
{
if(x.y==y.y)return x.x<y.x;
return x.y<y.y;
}
int n,f[maxn],ans=;
int find(int x)
{
int l=,r=x;
while(l+<r)
{
int mid=(l+r)>>;
if(s[mid].y<s[x].x)l=mid;
else r=mid;
}
if(s[r].y<s[x].x)return r;
if(s[l].y<s[x].x)return l;
return -;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();
for(int i=;i<=n;i++)s[i].x=read(),s[i].y=read();
sort(s+,s++n,wy);
for(int i=;i<=n;i++)
{
int j=find(i);
if(j!=-)f[i]=max(f[i-],f[j]+s[i].y-s[i].x+);
else f[i]=max(f[i-],s[i].y-s[i].x+);
}
for(int i=;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
return ;
}
其实呢这道题让学长来看就是一个01背包直接看出来,可能对dp十分的熟悉吧。
这里我采用临街表存相同的点的右坐标加上当前的区间的值即可这样的话每次访问到当前的j(正序循环)如果j连边的话就行更新,当然在更新之前要把上个f[i-1]过继下来因为满足了单调性所以可以这样最好f[m]即为最大值。很简单超快的!
#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
int n,m,lin[maxn],ver[maxn],len=,nex[maxn],f[maxn];
void add(int x,int y)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
}
struct bwy
{
int x,y;
}s[maxn];
int main()
{
//freopen("1.in","r",stdin);
n=read();
for(int i=;i<=n;i++)
{
s[i].x=read();
s[i].y=read();
m=max(m,s[i].y);
add(s[i].y,s[i].y-s[i].x+);
}
for(int i=;i<=m;i++)
{
f[i]=f[i-];
for(int j=lin[i];j;j=nex[j])
{
f[i]=max(f[i-ver[j]]+ver[j],f[i]);
}
}
printf("%d\n",f[m]);
return ;
}
明知不可为而为之!
dp进阶——饥饿的奶牛的更多相关文章
- 题解 P1868 【饥饿的奶牛】
题目链接:P1868 饥饿的奶牛 题面 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧 ...
- codevs 1345 饥饿的奶牛
1345 饥饿的奶牛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description John养了若干奶牛,每天晚上奶牛都要进食.由于条件比较 ...
- BZOJ1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛
1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 665 Solved: 419 ...
- BZOJ 1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛( LIS )
裸的LIS ----------------------------------------------------------------- #include<cstdio> #incl ...
- 洛谷P1868 饥饿的奶牛
P1868 饥饿的奶牛 题目描述 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草.你 ...
- 华东交通大学 2019 I 不要666 数位dp进阶
Problem Description 题库链接 666是一个网络用语,用来形容某人或某物很厉害很牛.而在西方,666指魔鬼,撒旦和灵魂,是不吉利的象征.所以邓志聪并不喜欢任何与6有关的数字.什么数字 ...
- 【Luogu】P1868饥饿的奶牛(DP)
题目链接 话说我存一些只需要按照一个关键字排序的双元素结构体的时候老是喜欢使用链式前向星…… DP.f[i]表示前i个位置奶牛最多能吃到的草.转移方程如下: f[i]=f[i-]; f[i]=max( ...
- [LUOGU1868] 饥饿的奶牛 - dp二分
题目描述 有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字. 现用汉语翻译为: 有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草.你可以选择任意区间但不能有 ...
- [luoguP1868] 饥饿的奶牛(DP)
传送门 先把所有区间按照左端点排序 f[i]表示区间0~i的最优解 #include <cstdio> #include <iostream> #include <alg ...
随机推荐
- 【Linux高级驱动】网卡驱动分析
两个重要的结构体简单介绍 *sk_buff 如果把网络传输看成是运送货物的话,那么sk_buff就是这个“货物”了,所有经手这个货物的人都要干点什么事儿,要么加个包装,要么印个戳儿等等.收货的时候就要 ...
- LeetCode: Valid Parentheses 解题报告
Valid Parentheses Given a string containing just the characters '(', ')', '{', '}', '[' and ']', det ...
- android:onClick都做了什么
同步发表于 http://avenwu.net/viewinject/2015/01/28/android_onclick/ 相信大家都知道在layout里面可以给view写android:onCli ...
- [Python] 07 - Statements --> Functions
故事背景 一.阶级关系 1. Programs are composed of modules.2. Modules contain statements.3. Statements contain ...
- IOS开发之--iPhone XR,iPhone XS Max适配
因为iPhone X和iPhone XS的尺寸比是一样的,只需要把这两张图片补上就行. 具体原理性的东西就多说了,因为iPhoneX系列都一样,本文只说明一下具体怎么做,要适配屏幕,首先得让他以正确的 ...
- Java处理Exception无法捕获的异常
场景: 使用try...catch(Exception e){}来捕获异常,执行过程中线程中断或阻塞了,但是catch块中却并没有捕获到异常信息. try{ // 此处可能是调用一个远程的接口,或是调 ...
- Fiddler 安装与配置
可以直接访问官网下载安装包 https://www.telerik.com/download/fiddler ,安装后需要配置浏览器的代理服务器为 Fiddler: 以谷歌浏览器为例:[设置]---[ ...
- Android编译环境——ubuntu12.04上android2.3.4编译错误以及解决
Android编译环境——ubuntu12.04上android2.3.4编译错误以及解决 分类: android应用开发2013-08-21 09:20 4222人阅读 评论(3) 收藏 举报 li ...
- MySQL PARTITION 分区
MySQL HASH分区 http://www.cnblogs.com/chenmh/p/5644496.html RANGE分区:http://www.cnblogs.com/chenmh/p/56 ...
- 【!Important】Java线程死锁查看分析方法
一.Jconsole Jconsole是JDK自带的图形化界面工具,使用JDK给我们提过的工具JConsole,可以通过cmd打开命令框然后输入Jconsole打开图形工具 然后点击检测死锁就可以查看 ...