二分 POJ 2456--Aggressive cows

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LMengi000/article/details/81451748

                                                                                               Aggressive cows

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 20261   Accepted: 9604

Description

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). 

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Line i+1 contains an integer stall location, xi

Output

* Line 1: One integer: the largest minimum distance

Sample Input

5 3
1
2
8
4
9

Sample Output

3

Hint

OUTPUT DETAILS: 

FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3. 

Huge input data,scanf is recommended.

Source

USACO 2005 February Gold

题意:有n个栅栏,坐标为 x1,...,xN,有C头牛,把没头牛放在离其他牛尽可能远的地方,也就是最大化最近的两头牛。

类似的最大化最小值或者最小化最大值问题,用二分法解决。

第一种方法采用的是看栅栏 
栅栏排好序之后是 
栅栏坐标 1 2 4 8 9
下标     0 1 2 3 4
1——9这些栅栏里面根据坐标可以放牛
从头开始放 L=0 R=9;
用二分法,再次放的时候 mid=L+(R-L)/2,mid=4
假设间隔为4的话,在这些栅栏里面放牛,看C个牛是否能放开
 1 2 4 8 9
放    放 
如果放不开,证明间隔太大了;如果能放开,证明间隔合法但不能证明间隔是最大间隔,还要再试放
mid=4显然放不开,修改R的值,R=4;此时 L=0 R=4 mid=2; 
再试放牛,间隔为2
 1 2  4  8 9
放   放 放 
显然能放开 ,但是不能说明2就是最大的距离,还要继续试放牛 
修改L=2,R=4; mid=3
 1 2 4  8 9
放  放 放 
能放开,还是要继续放,
L=3,R=4;此时不再满足while循环条件while(R-L>1),
综上:当间隔为3时,是放牛的最大距离。 
 


#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn=1e5;
int n,c;
int a[maxn];
int check(int dir)
{
	int cows=1;
	int precow=0;
	for(int i=1;i<n;i++) //看栅栏的下标 
	{
		if(a[i]-a[precow]>=dir)//如果后一个牛与前一个牛之间的距离达到了dir
		{
			cows++;//把牛放进去
			precow=i;//记录刚刚放入的牛的位置,方便再放下一个牛
		}
		if(cows>=c)
		{
			return 1;
		}
	}
	return 0;
}
int main()
{
	scanf("%d%d",&n,&c);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int L=0,R=a[n-1];
	while(R-L>1)
	{
		int mid=L+(R-L)/2;
		if(check(mid))
		{
			L=mid;	
			cout<<"L="<<L<<endl;
		 } 

		else
		{
		 R=mid;			
		  cout<<"R="<<R<<endl;
		}

	}
	printf("%d\n",L);
	return 0;
}

第二种做法:看牛 
栅栏排好序之后是 
栅栏坐标 1 2 4 8 9
下标     0 1 2 3 4
把牛放入的坐标的范围是0 <= xi <= 1,000,000,000
所以最先放牛的位置是0,最后一个放牛的最远位置是1e9
L=0,R=1e9+10(通常把范围放大看,包括1e9)
在L--R的范围内二分,然后在check函数中,判断以mid距离放牛,是否能放开

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
const int INF=1e9+10;
const int maxn=1e5;
int n,c;
int a[maxn];
bool check(int dir)
{
	int precow=0; //第一个放牛的位置,用precow来记录 
	for(int i=1;i<c;i++) //牛的个数,通过判断条件,看把牛放在哪个栅栏里 
	{
		  int j=precow+1;//后一个放牛的位置,用j来记录 
		while(j<n && a[j]-a[precow]<dir)//如果后一个放牛的位置没有越界,并且前一个放牛的位置与后一个放牛的位置之间的距离为dir,就不再循环 
		{
		      j++;		
		//	  cout<<"j="<<j<<endl;	
		}
		if(j>=n) //判断是否越界 
		  return false;
		else
		  precow=j;
	}
	return true;
}
int main()
{
		scanf("%d%d",&n,&c);
		 int ans;
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a,a+n);
	int L=0,R=INF;//R=a[n-1]也是可以的,只不过范围大小不同 
	while(R-L>1)
	{
		int mid=L+(R-L)/2;
		if(check(mid))
		{
			L=mid;	
		//	cout<<"L="<<L<<endl;
		 } 

		else
		{
		 R=mid;			
		  //cout<<"R="<<R<<endl;
		}

	}
	printf("%d\n",L);
	/*这样写二分,最后输出的结果不是L或者R,而是L+1或者L-1
	  所以我们应该加一个计数变量ans来记录mid 
	 		 while(L<=R)
	{
		int mid=L+(R-L)/2;
		if(check(mid))
		{
		     ans=mid; //要在上面定义ans 
			L=mid+1;	
		//	cout<<"L="<<L<<endl;
		 } 

		else
		{
		    R=mid-1;			
		  //cout<<"R="<<R<<endl;
		}
	}
	printf("%d\n",ans);
	*/
	return 0;
}

注意的点:

1.写二分的方法:用的方法不同,输出不同。

2.看分栅栏和分牛两种方法,

猜你喜欢

转载自blog.csdn.net/LMengi000/article/details/81451748
今日推荐