1. 程式人生 > >poj2456- Aggressive crows poj3258

poj2456- Aggressive crows poj3258

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;
}