疯鱼尾的短学期第二天

    技术2023-12-15  80

    二分法习题报告(一)

    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是大于号。这样一看就很好理解了。

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

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

    Processed: 0.013, SQL: 9