标签:
有N个居民点在一条直线上,每个居民点有一个x表示坐标,y表示居民点的现有居民数。现在要求将居民点的居民重新分配,每个居民点的居民最远迁移的距离为R,要求分配完之后,居民点中居民数最多的居民点的居民数最少。求出居民数最多的居民点的居民数的最少值。
求最大最小值/最小最大值的问题,可以尝试二分法,给出边界,取边界中点作为尝试值,判断尝试值是否满足要求,根据是否满足,不断调整边界,最后得到最大最小值/最小最大值。
自己做的时候,只知道具体的框架,但是没有解出来,最后参考了
居民迁移-二分+贪心 解法。
首先将所有居民点的原有居民数,以及居民点能够到达的最左和最右边界提取出来,用于后续的安置。则问题为:将各个居民点的居民,重新分配到各个安置点,在分配的时候,两个指针,一个指向可以安置的居民点的位置,一个指向当前被分配的居民点的位置。
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define N 100005
struct Point{
int x;
int y;
};
Point points[N];
//left:居民点的居民能够到达的最左边的位置, right居民点的居民能够到达的最右边的位置
//num:居民点的原有的居民数目
struct Seg{
int left, right, num;
};
Seg segs[N];
bool cmp(Point a, Point b){
return a.x < b.x;
}
/*判断是否存在分配方案,使得每个居民点的居民数最大为middle
分配之前,将每个居民点(x, y) 转换为 (left, right, num),然后对(left, right, num)数组进行分配。
将(left, right, num) 将num个居民根据其所能到达的最远位置left,right ,分配到其所能到达的居民点去。
pos 表示当前需要对哪个seg(left, right, num)进行分配; num表示当前需要分配的(left, right, num)居民点的现有居民数。
从左到右,遍历所有的居民点 points,进行安置 segs.
*/
bool canSet(int n, int R, int middle){
int pos = 0, num = segs[0].num;
//pos 为当前需要分配的seg
for (int i = 0; i < n; i++){
//当前可以分配居民的安置点
int p = points[i].x;
int volume = middle;
//如果当前的安置点p大于pos所能到达的最远边界,说明pos在之前没有被分配完,则此次分配失败
if (segs[pos].right < p)
return false;
int j;
//尝试将各个seg的居民,分配到 当前可以分配的安置点p
for (j = pos; j <= n; j++){
if (j == n) //都分配完
return true;
//要分配的居民点已经无法到达安置点p,则分配到下一个安置点
if (segs[j].left > p){
pos = j;
num = segs[j].num;
break;
}
int cnt;
if (j == pos)
cnt = num;
else
cnt = segs[j].num;
volume -= cnt;
if (volume < 0){//安置点无法容纳更多的居民,则分配到下一个安置点
pos = j;
num = -volume;
break;
}
}
}
return false;
}
int main(){
int T, n, R, min, max;
scanf("%d", &T);
while (T--){
scanf("%d %d", &n, &R);
min = 1 << 30, max = 0;
for (int i = 0; i < n; i++){
scanf("%d %d", &points[i].x, &points[i].y);
min = min < points[i].y ? min : points[i].y;
max = max > points[i].y ? max : points[i].y;
}
//将居民点按照位置从小到大排序
sort(points, points + n, cmp);
//根据原有的居民点的居民数,以及居民所最远迁移的距离,初始化segs数组,得到每个居民点能够到达的最远边界,以及原有的居民数目
for (int i = 0; i < n; i++){
segs[i].left = points[i].x - R;
segs[i].right = points[i].x + R;
segs[i].num = points[i].y;
}
while (min < max){
int mid = (min + max) / 2;
//判断是否存在分配方案,使得每个居民点最多有mid个居民
if (canSet(n, R, mid)){
max = mid;
}
else
min = mid + 1;
}
printf("%d\n", max);
}
return 0;
}
标签:
原文地址:http://www.cnblogs.com/gtarcoder/p/5518817.html