算法-二分

1 篇文章 0 订阅

暑期学习—二分
题目描述(poj-3258)
Every year the cows hold an event featuring a peculiar version of hopscotch that involves carefully jumping from rock to rock in a river. The excitement takes place on a long, straight river with a rock at the start and another rock at the end, L units away from the start (1 ≤ L ≤ 1,000,000,000). Along the river between the starting and ending rocks, N (0 ≤ N ≤ 50,000) more rocks appear, each at an integral distance Di from the start (0 < Di < L).

To play the game, each cow in turn starts at the starting rock and tries to reach the finish at the ending rock, jumping only from rock to rock. Of course, less agile cows never make it to the final rock, ending up instead in the river.

Farmer John is proud of his cows and watches this event each year. But as time goes by, he tires of watching the timid cows of the other farmers limp across the short distances between rocks placed too closely together. He plans to remove several rocks in order to increase the shortest distance a cow will have to jump to reach the end. He knows he cannot remove the starting and ending rocks, but he calculates that he has enough resources to remove up to M rocks (0 ≤ M ≤ N).

FJ wants to know exactly how much he can increase the shortest distance before he starts removing the rocks. Help Farmer John determine the greatest possible shortest distance a cow has to jump after removing the optimal set of M rocks.

题意
给了河的长度,石头数量,可删除的石头数量,求解删除指定数量的石头后石头间的最小距离的最大值是多少

题解
截止目前学的一些二分,可以用二分解决至少两类问题
1.查找
2.极值优化
这个是最大化最小值问题,是一个典型的二分问题,所以采用二分来解(同理可求解最小化最大值问题)
二分中,首先要确定二分具体找的东西和限制条件,因为二分终究是一个查找算法,那么,不妨就将目标值作为二分中的mid值,这样每次目标值都会变化,只要出现了合适的目标值就可以结束程序或者完成了一次优化。
那么,在这个题中,目标值就是石头间的最小距离。之后,我们可以根据目标值确定查找的上下限,本题中,理论上最优的上下限应该是石头间的最大差值和最小差值(上下限的确定要根据目标值),但是,如果这样需要O(n^2)的时间来找,那么不妨令左边界l为0,有边界r为数组中的最大元素,这样虽然不精确,但只需要多进行几次二分就可以了,时间上是大大节省的,而实际上,寻找上下限并不是需要十分精准,因为对于大量数据来说,精准寻找太麻烦而且没必要,只需要包含进去即可,因为二分所需的时间更少。至此,我们已经完成了上下限的确定和目标值的确定,那么就需要根据限制条件来改变目标值。
在本题中,限制条件(往往是多给的那个条件)是去掉的石头的数量,那么可以根据要删除的石头的数量进行改变。这里我们需要先进行排序,因为要过河,而且只能单向走,所以必然要从小到大进行,然后我们可以直接进行O(n)遍历,将后面的元素顺序与第一个元素作差,如果小于mid呢么说明它小于最小值,那么有一个石头是需要删除的;如果大于mid那么就说明mid仍为最小值,那么久可以继续遍历,但这时要更新减去的元素为当前的元素,因为上一个元素减去它已经大于mid,而有排序后,再用上一个元素没有意义了,但用这个元素做差可以确定下一个元素的情况

	代码如下
#include <iostream>
#include <cstring>
#include <algorithm>
#include <iomanip>
/*
目前了解的二分可以解决两类问题,查找位置,最值优化
这是一个典型的最大化最小值问题,那么采取二分处理
*/
using namespace std;
int a[50004];
int b[50004];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,i,j,k,t,m,dis,s;
    cin>>dis>>n>>m;
    memset(a,0,sizeof(a));
    for(i=1;i<=n;i++)
        cin>>a[i];
    int l,r,mid;
    a[n+1]=dis;
    sort(a+1,a+n+2);//这个二分需要排序,因为是
    l=0,r=dis;
    while(l<=r){
            t=0;
            k=0;
        mid=l+(r-l)/2;
        for(i=1;i<=n+1;i++)
            {
                if(a[i]-a[k]<mid) t++;
                else k=i;
            }
        if(t>m) r=mid-1;
        else{
            l=mid+1;
            s=mid;
        }
    }
    cout<<s<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值