Poj 2456(二分搜索 + 贪心)
题意:
一共有n间牛舍,m头牛,x[i]代表每个牛舍的位置;要求把所有的牛都放到牛舍里,并且最大化最近的两头牛之间的距离。
思路:
二分枚举最近的两头牛之间的距离,判断在任意的两头牛之间的距离大于或等于该距离下能否将所有的牛放进牛舍。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 5 using namespace std; 6 7 int n, m; 8 int x[100005]; 9 bool C(int d)//判断当最近的两头牛之间的距离d时,能否将所有的牛放进牛舍。 10 { 11 int last = 0;//目前最晚放进去牛的牛舍编号(编号0到n - 1)。 12 for (int i = 1; i < m; i++) 13 { 14 int crt = last + 1; 15 while (crt < n && x[crt] - x[last] < d) 16 { 17 crt++; 18 } 19 if (crt == n) 20 { 21 return false; 22 } 23 last = crt; 24 } 25 return true; 26 } 27 28 int main() 29 { 30 scanf("%d%d", &n, &m); 31 for (int i = 0; i < n; i++) 32 { 33 scanf("%d", &x[i]); 34 } 35 sort(x, x + n);//对牛舍位置排序。 36 int low = 1, high = x[n - 1] - x[0];//最小距离为1,最大距离为x[n-1] - x[0]。 37 while (low <= high) 38 { 39 int middle = low + (high - low) / 2; 40 if (C(middle)) 41 { 42 low = middle + 1; 43 } 44 else 45 { 46 high = middle - 1; 47 } 48 } 49 printf("%d\n", high); 50 }
注意:
代码中唯一需要注意的地方是为何输出的是high而不是low。首先看while循环的结束条件(low > high),循环结束后low == high + 1。
我们需要注意的是while循环的最后一层循环;正是这层循环造成了low == high + 1。最后一层循环有两种情况。
1:C(middle)为真,即两头牛之间最近距离为middle时,可以将所有的牛放进牛舍;此时,程序会执行 low = middle + 1,并结束循环。
我们已经知道循环结束后 low == high + 1,所以high == middle,high满足要求,且为最大值。
2:C(middle)为假,即两头牛之间最近距离为middle时,不能将所有的牛放进牛舍;此时,程序会执行 high = middle – 1,并结束循环。
我们已经知道循环结束后 low == high + 1,所以low == middle,low肯定不满足我们的条件,不急,我们再思考思考low是怎么到达现在
这个位置的。要知道在最后一次循环以前的多次循环中,肯定有一次或多次(C(middle)为真)的情况,因为m <= n。只要有这种情况
,就肯定执行过(low = middle + 1)这条语句,而high的值与最后一次这种情况的middle相等,说明high满足要求,且为最大值。