1. 程式人生 > >HihoCoder 1053 : 居民遷移 二分+貪心+雙指針

HihoCoder 1053 : 居民遷移 二分+貪心+雙指針

一行 隨著 循環 space 相同 name .com 範圍 位置

居民遷移

時間限制:3000ms 單點時限:1000ms 內存限制:256MB

描述

公元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

鋪墊:

如果沒有距離不超過R的限制,直接總和除個數即可。

如果知道上界,像“紙牌移動”一樣貪心就行。

求最大值最小化,二分既可。

正題:

初步思路:預處理每個點的範圍,然後最大流來判斷是否滿流。

優化思路:由於範圍肯定是連續處理得到最優,所以用雙指針。

自己YY的雙指針代碼,醜是情有可原的,不過1A了,醜不醜無所謂lia。

不懂雙指針的可以去看hihocoder1607辣。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100010;
int a[maxn],b[maxn];
int L,R,r,n;
struct in
{
    int x;
    int y;
}s[maxn];

bool cmp(in a,in b){
    return a.x<b.x;
}

bool check(int u)
{
     int p=1,m=1;//p是待裝,m是容器指針
     for(int i=1;i<=n;i++){
          a[i]=s[i].y;b[i]=0;//a是待裝,b是容器
     }
     while(p<=n&&m<=n){
          while(p<=n&&s[m].x-s[p].x>r) {
               if(a[p]>0) return false;
               p++;
          }
          while(m<=n&&p<=n){
               if(s[p].x-s[m].x>r||b[m]==u) { m++;break; }
               int tmp=min(a[p],u-b[m]);
               a[p]-=tmp; b[m]+=tmp;
               if(a[p]==0) p++;
          }
     }
     for(int i=1;i<=n;i++) if(a[i]>0) return false;
     return true;
}
int main()
{
      int i,j,T;    
      scanf("%d",&T);
      while(T--){
            L=R=1;
            scanf("%d%d",&n,&r);
            for(i=1;i<=n;i++){
                scanf("%d%d",&s[i].x,&s[i].y);
                R=max(R,s[i].y);
            }
            sort(s+1,s+n+1,cmp);
            while(L<R){
                int mid=(L+R)/2;
                if(check(mid)) R=mid;
                else L=mid+1;
            }
            printf("%d\n",L);
      }
      return 0;
}
 

HihoCoder 1053 : 居民遷移 二分+貪心+雙指針