描述
公元2411年,人类开始在地球以外的行星建立居住点。在第1326号殖民星上,N个居住点分布在一条直线上。为了方便描述,我们设第i个居住点的位置是Xi,其中居住着Yi位居民。随着冬季的到来,一些人口较多的居住点的生态循环系统已经开始超负荷运转。为了顺利度过严冬,殖民星上的居民一致同意通过转移到人口较少的居住点来减轻人口众多的居住点的负荷。
遗憾的是,1326殖民星的环境非常恶劣。在冬季到来前,每个居民点的居民最远能迁移到距离不超过R的居民点。1326殖民星的居民希望知道,如何安排迁移才能使完成迁移后人口最多的居民点人口最少?
注意有可能存在多个居民点位置相同。
输入
第一行包含一个整数T(1 <= T <= 10),代表测试数据的组数。
每组数据的第一行包含2个整数N(1 <= N <= 100000)和R(0 <= R <= 10^9)。
以下N行每行包含两个整数,Xi和Yi(0 <= Xi, Yi, <= 10^9)。
输出
对于每组数据输出迁移后人口最多的居民点人口最少可能的数目。
样例输入
3
5 1
10 80
20 20
30 100
40 30
50 10
5 10
10 80
20 20
30 100
40 30
50 10
5 20
10 80
50 10
20 20
30 100
40 30
样例输出
100
50
48
思路:
我们通过二分来求解,对mid进行一个判断看是否满足题目条件。这个题有judge函数中去判断时候满足条件的时候需要用到贪心和双指针。贪心是说,我们每次尽量把前面的居民点填满(也就是让其居民点的人数尽量的接近x),然后用j指针记录一先最前面不满x个人的居民点的坐标,我们用数组a来记录当前可以移动的人数,用数组b来记录当前要留在这个居民点的人数,然后继续判断如果在范围内的话,就把当前居民点的人数移动到j位置。最后判断一下a数组中每个居民点的可以移动的人数是否>0,大于0意味着就不满足条件(也就是说,当遍历完整个数组,b数组中的每个位置都被填满成x,这时候a数组中仍然有可移动的人数的话,那说明ans应该比x要大) return false 否则 return true
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1e5+5;
struct node
{
int x,y;
}s[maxn];
int a[maxn],b[maxn];
int t,n,r,low,high;
bool cmp(node a,node b)
{
return a.x < b.x;
}
bool judge(int x)
{
for (int i = 0; i < n; ++i) {
a[i] = s[i].y; // 可以移动的人数
b[i] = 0;// 不能移动的人数
}
int i = 0,j = 0;
while(i < n && j < n) {
if(abs(s[i].x - s[j].x) > r) {
if( j > i) return false;
++j;
}
else {
if (a[i] + b[j] <= x) {
b[j] += a[i];
a[i] = 0;
++i;
}
else {
a[i] -= x - b[j];
b[j] = x;
++j;
}
}
}
for (int i = 0; i < n; ++i)
if (a[i] > 0) return false;
return true;
}
int Search(int low,int high)
{
while(low < high) {
int mid = (low + high) / 2;
if(judge(mid)) high = mid;
else
low = mid + 1;
}
return low;
}
int main()
{
cin >> t;
while(t--) {
cin >> n >> r;
for (int i = 0; i < n; ++i)
cin >> s[i].x >> s[i].y;
sort(s,s+n,cmp);
low = 0,high = 1e9;
int res = Search(low,high);
cout << res <<endl;
}
return 0;
}