疯牛
时间限制:1000 ms | 内存限制:65535 KB
难度:4
- 描述
- 农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,...,xN (0 <= xi <= 1,000,000,000).
但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?- 输入
- 有多组测试数据,以EOF结束。
第一行:空格分隔的两个整数N和C
第二行——第N+1行:分别指出了xi的位置 输出 - 每组测试数据输出一个整数,满足题意的最大的最小值,注意换行。 样例输入
-
5 3 1 2 8 4 9
样例输出 -
3
-
题意要表达的是:把C头牛放到N个带有编号的隔间里,使得任意两头牛所在的隔间编号的最小差值最大。例如样例排完序后变成1 2 4 8 9,那么1位置放一头牛,4位置放一头牛,它们的差值为3;最后一头牛放在8或9位置都可以,和4位置的差值分别为4、5,和1位置的差值分别为7和8,不比3小,所以最大的最小值为3。
分析:这是一个最小值最大化的问题。先对隔间编号从小到大排序,则最大距离不会超过两端的两头牛之间的差值,最小值为0。所以我们可以通过二分枚举最小值来求。假设当前的最小值为x,如果判断出最小差值为x时可以放下C头牛,就先让x变大再判断;如果放不下,说明当前的x太大了,就先让x变小然后再进行判断。直到求出一个最大的x就是最终的答案。
-
cpp:
#include <stdio.h> #include <stdlib.h> #define Max_size 100020 int x[Max_size]; int N,C; int com(const void *a,const void *b)//排序 {return *(int *)a-*(int *)b; } bool Judge(int v) {//v表示两牛之间最小的距离值int i;int num=0;//房子编号int t;for(i=1;i<C;i++)//对牛计数{t=num+1;while(t<N&&x[t]-x[num]<v)//t跳出时 t==N说明列举了 num之后的所有房子都无法满足两房子之间距离<=v值t++;//反之,则说明找到了满足条件的房子if(t==N)return false;num=t;}return true; } int main() {int i;int bottom,top;int mid;while(~scanf("%d%d",&N,&C)){for(i=0;i<N;i++)scanf("%d",x+i);qsort(x,N,sizeof(x[0]),com);//因为每个房间的坐标是混乱的,所以对每个房间的坐标进行小到大排序bottom=0;top=(x[N-1]-x[0])*2;//确定上界和下界while(top-bottom>1){mid=(top+bottom)/2;if(Judge(mid))bottom=mid;//mid值能满足条件 说明答案的区间为[mid,top)else top=mid;//mid 值不能满足条件 说明答案的区间为(bottom,mid)}printf("%d\n",bottom);}return 0; }
#include<stdio.h> #include <stdlib.h> int cmp(const void*a,const void *b) {return *(int *)a-*(int *)b; } int a[1000001]; int main() {int i,c,h,sum;while(scanf("%d%d",&h,&c)!=EOF){for(i=0;i<h;i++)scanf("%d",&a[i]);qsort(a,h,sizeof(a[0]),cmp);int max=a[h-1]-a[0];//二分搜索的范围,这里Max是两头牛相距的最大范围 int min=0,mid;while(max>=min){mid=(min+max)/2;//截取中间的这个点 int m=1,n=0;sum=0;while(m<h){if(a[m]-a[n]>=mid)//领M个元素与第N个元素比较,如果大于这个等于Mid,说明这个距离可以放牛, { // 然后把N的值改变,n=m,让下一个m++元素与这个n比较, sum++; //同时记录符合这个距离的情况有几种,sum++; n=m;}m++;}if(sum>=c-1)//如果这种情况是大于c-1头牛的,说明答案在 【mid+1,max】中 {min=mid+1;}else //如果这种情况是小于c-1头牛的,说明答案在 【min,mid-1】中 {max=mid-1;}}printf("%d\n",min-1); }return 0; }
-
-
-
这个是贪心和二分.二分查找又是折半查找,首先,元素是升序排列,每次查找中间元素和待查找元素进行比较,如果相同,就返回中间元素的位置值,如果不相同且中间元素大于待查找元素就从右边开始,如果不相同且中间元素小于待查找元素就从左边开始,适用于不经常变动而且查找频繁的有序列表。
- 有多组测试数据,以EOF结束。