poj 2456 Aggressive crows
此题核心在于二分搜索牛之间的距离,然后贪心地放牛作为判断是否满足条件的依据。
贪心:在满足两牛之间距离不小于d的情况下,如何尽可能多放牛?(关键,剔除了很多情况)
贪心之前往往要排序。
二分:二分搜索找出d,方便判断。
①注意整数二分的写法,有些写法有可能会陷入死循环
②关于最大化最小值和最小化最大值问题,到底取left还是right?
分解题意。
看二分写法,我的写法一般二分取left。刚开始被最大值最小化搞晕了,其实二分已经包含把最小值最大化的过程。
#include<iostream>
#include<algorithm>#include<stdio.h>
using namespace std;
int X[100005];
int N,M;
bool Judge(int d)
{
int cur=0;
int i=cur+1;
int sum=1;
while(i<N&&cur<N)//还能被找到, 贪心下每头牛只要确定前面的位置,至于它放后面的位置就不是最优情况。
{
//cout<<"!"<<endl;
if(X[i]-d>=X[cur])//这里严格上应该是>号
{
cur=i;
i=cur+1;
sum++;
//cout<<d<<"de"<<cur<<"he"<<i<<"hewei"<<sum<<endl;
}
else
i++;
}
//if(sum==M)cout<<"yes"<<endl;
if(sum>=M) //前面取点时候虽然头数相等,但不一定取到mid,而且要最大化最小值的话,所以要往大的搜
return true;
//cout<<"yes";
return false;
}
int main()
{
int l=0;
int r=1000000000;
int mid;
cin>>N>>M;
for(int i=0;i<N;i++)
{
scanf("%d",&X[i]);//10^5的输入一定要用scanf!!!不然超时
}
sort(X,X+N);//贪心之前常常要排序
for(int i=0;i<35;i++)//控制二分次数,很好用
// while(l<r)//死循环
//while(l<r-1)//l、r整数适用
{
mid=(l+r)/2;
//cout<<mid<<endl;
if(Judge(mid))
l=mid;
else
r=mid;
}
cout<<l<<endl;
}
poj3258 River Hopscotch
与上题区别仅在于多了一个终点,虽然终点不可删,但其实贪心的过程完全一样。
#include <iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int L,M,N;
int a[5000010];
bool Judge(int d)
{
int cur=0;
int i=1;
int sum=1;
while(i<=N+1&&cur<=N+1)
{
if(a[i]-a[cur]>=d)//这里严格意义是大于号
{
cur=i;
i=cur+1;
sum++;
}
else
i++;
}
//cur=N;
// i=N-1;
//int sum2=1;
//while(i>0&&cur>0)
//{
// if(a[cur]-a[i]>=d)
// {
// cur=i;
// i=cur-1;
// sum2++;
// }
// else
// i--;
// }
// cout<<d<<" de"<<sum<<endl;
if(sum>=N-M+2)//等于号也要往大的找,同上
return true;
else
return false;
}
int main()
{
cin>>L>>N>>M;
a[0]=0;
for(int i=1;i<=N;i++)
{
scanf("%d",&a[i]);
}
a[N+1]=L;
sort(a,a+N+2);
int l=0;
int r=1000000001;
int mid;
for(int i=0;i<100;i++)
{
mid=(l+r)/2;
if(Judge(mid))
l=mid;
else
r=mid;
}
cout<<l<<endl;
}