疯鱼尾的短学期第二天

二分法习题报告(一)

1.饥饿的奶牛

链接: 饥饿的奶牛.

解题思路:

第一步:排序

按照右端点为第一关键字,左端点为第二关键字排序。
第二步:预处理数组p

这里是关键了!众所周知,dp的各个子结构之间是不能有关联的。我们的dp是按照区间进行dp,所以对于每一个区间k,都要计算出p[k]=q,它满足:

①0≤q<k

②选择区间k之后,区间1,2,3…q仍然可以选择

③选择区间k之后,区间q+1,q+2…k-1不能选择

我们只需要快速找到一个区间,使得该区间的右端点在k的左端点左边即可。

这样就可以在dp时,快速查询在执行“选”的决策时转移的区间。

另外这一步有一个细节:n的规模大,在寻找区间时需要二分而不能暴力寻找,否则会T掉第三个点。
第三步:dp

方程是非常简单的(前面的步骤全部都是为了dp)。每个区间只有两种决策(即选与不选)。

设dp[k]为只考虑前k个区间时最多能选到多少个点。如果选k,转移到dp[p[k]]+right[k]-left[k]+1;如果不选k,转移到dp[k-1]。

代码:
#include <iostream>
#include <algorithm>
#define sta a
#define end c//后来我才知道end是保留字,无奈
using namespace std;
long long sta[150001],end[150001],b,n,p[150001],dp[150001];
bool cmp1(int i,int mid1,int mid2)
{
    return end[i]<mid1 || (end[i]==mid1 && sta[i]<mid2);
}
bool cmp2(int j,int mid1,int mid2)
{
    return end[j]>mid1 || (end[j]==mid1 && sta[j]>mid2);
}
void sort(int l,int r)
{
    int i=l,j=r,mid1=end[(i+j)/2],mid2=sta[(i+j)/2];
    while(i<=j)
    {
        while(cmp1(i,mid1,mid2))i++;
        while(cmp2(j,mid1,mid2))j--;
        if(i<=j)
        {
            swap(sta[i],sta[j]);
            swap(end[i],end[j]);
            i++;j--;
        }
    }
    if(l<j)sort(l,j);
    if(i<r)sort(i,r);
}
int binarysearch(int l,int r,int val)
{
    int mid;
    while(l<r)
    {
        mid=l+((r+1-l)>>1);
        if(end[mid]<val)l=mid;
        else r=mid-1;
    }
    return l;
}
int main()
{
    int q;
    cin>>b;
    for(int i=1;i<=b;i++)cin>>sta[i]>>end[i];
    sort(1,b);
    p[1]=0;sta[0]=0;end[0]=-1;dp[0]=0;
    for(int i=2;i<=b;i++)
    {
        q=i-1;
        q=binarysearch(0,q,sta[i]);
        p[i]=q;
    }
    for(int i=1;i<=b;i++)dp[i]=max(dp[i-1],dp[p[i]]+end[i]-sta[i]+1);
    cout<<dp[b];
    return 0;
}
总结:

首先这个代码不是我写的,我写了将近一个多小时还是没有一个很好的方法能通过测试。最后还是看了网上的解题思路。虽然没写出来,好好总结一样的有收获。

binarysearch()函数:作用是,在区间0到q之间找到最大的一个j使得end[j]<sta[i],用到二分的思想,大大降低了时间复杂度。

代码的难点在我看来不在二分,首先是要想到用动态规划,其实我感觉对于动态规划学的比较好的人来说,一个不难看出来。但是对于我这种小菜鸡,还真没看出来。。。所以到了动态规划的章节要好好看看。

最后就是在我心里的重头戏了,怎么样按照右端点为第一关键字,左端点为第二关键字排序。反正我是不敢想的,能力限制了我的想象。。。。下面就来好好的解释一下别人是怎么操作的。

首先是两个函数comp1和comp2。comp1:相当于是判断小于。comp2:相当于是判断大于。这个我硬看了半天没看明白,后来自己随便举了一个栗子,手动运行了一下就明白了。。。这也算是领悟到了一个看代码的方法。

然后是sort函数,其实它就是一个就是一个快速排序。标兵是最中间的那个元素。然后comp1是小于号,comp2是大于号。这样一看就很好理解了。

这个串代码可谓是结合了动态规划,二分,快速排序为一体,怪不得我写到自闭。。。。

好了,还准备一天更完所有题目的,看样子今天只能更一题了。今天有事耽误了一早上时间。小菜鸡六级还没过,要去学学六级了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值