zoukankan      html  css  js  c++  java
  • hiho_1053_居民迁移

    题目大意

        有N个居民点在一条直线上,每个居民点有一个x表示坐标,y表示居民点的现有居民数。现在要求将居民点的居民重新分配,每个居民点的居民最远迁移的距离为R,要求分配完之后,居民点中居民数最多的居民点的居民数最少。求出居民数最多的居民点的居民数的最少值。

    题目分析

        求最大最小值/最小最大值的问题,可以尝试二分法,给出边界,取边界中点作为尝试值,判断尝试值是否满足要求,根据是否满足,不断调整边界,最后得到最大最小值/最小最大值。 
        自己做的时候,只知道具体的框架,但是没有解出来,最后参考了 
    居民迁移-二分+贪心 解法。 
        首先将所有居民点的原有居民数,以及居民点能够到达的最左和最右边界提取出来,用于后续的安置。则问题为:将各个居民点的居民,重新分配到各个安置点,在分配的时候,两个指针,一个指向可以安置的居民点的位置,一个指向当前被分配的居民点的位置。

    实现

    #include<stdio.h>
    #include<iostream>
    #include<string>
    #include<string.h>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<deque>
    #include<list>
    #include<set>
    #include<set>
    #include<map>
    #include<functional>
    #include<algorithm>
    using namespace std;
    int T;
    int N, R;
    struct Seg{
    	int left;
    	int right;
    	int num;
    };
    Seg segs[100005];
    int points[100005];
    bool Cmp(const Seg& seg1, const Seg seg2){
    	return seg1.left < seg2.left;
    }
    
    /*
    这道题一开始,想的是在居民点现有这么些居民数的基础上进行迁移,这样想会很乱。换一种想法:有N个居民集体,每个集体中有 num[i]个居民,且每个
    集体中的人的活动范围为 [left[i], right[i]],将这N个集体安放到N个点上。
    */
    bool canSet(int max_people){
    	//cur_seg_index 表示当前待迁移的居民点的序号, cur_pos 表示当前的目的点的序号
    	int cur_seg_index = 0, cur_pos = 0;
    	int cur_people = segs[0].num, cur_volume = max_people;
    	//将各个居民集体,迁移到各个居民点中去
    	//cur_people 表示当前要迁移的居民点中还剩余待迁移的居民的个数, cur_volume 表示当前要迁移到的目的地的空余位置
    	while (true){
    		if (cur_people <= cur_volume){//可以将当前点待迁移的所有居民都放置到 目的点
    			cur_seg_index++;
    			if (cur_seg_index == N)	//迁移完了所有带迁移的居民点,则成功
    				return true;
    			cur_volume -= cur_people; //当前目的点可以放置的居民数目减少
    			cur_people = segs[cur_seg_index].num; //当前待迁移点的居民数
    
    			//cur_seg_index 增加,可能导致目的点 在当前待迁移居民点的左侧 过远的位置,从而需要向右调整目的点
    			if (points[cur_pos] < segs[cur_seg_index].left){ 
    				while (points[cur_pos] < segs[cur_seg_index].left)
    					cur_pos++;
    				cur_volume = max_people; //同时更新 目的点可以放置的最大人数
    			}			
    		}
    		else{
    			//需要向下一个目的点放置剩余的居民
    			cur_pos++;
    			if (cur_pos == N) //没有可以放置的目的点了,返回失败
    				return false;
    			//当前待迁移的居民点无法再向 目的点进行迁移,返回失败
    			if (points[cur_pos] > segs[cur_seg_index].right)
    				return false;
    			//当前待迁移居民点 居民数减少
    			cur_people -= cur_volume;
    			//当前目的点可以存放居民数 为max_people
    			cur_volume = max_people;
    		}
    	}
    	
    	return true;
    }
    int main(){
    	scanf("%d", &T);
    	while (T--){
    		scanf("%d %d", &N, &R);
    		int end = 0;
    		for (int i = 0; i < N; i++){
    			scanf("%d %d", &points[i], &segs[i].num);
    			segs[i].left = points[i] - R;
    			segs[i].right = points[i] + R;			
    			end = max(end, segs[i].num);
    		}
    		sort(points, points + N);
    		sort(segs, segs + N, Cmp);
    		int beg = 0;
    		end++;
    		while (beg < end){
    			int mid = (beg + end) / 2;
    			if (canSet(mid)){
    				end = mid;
    			}
    			else
    				beg = mid + 1;
    		}
    		printf("%d
    ", beg);
    	}
    	return 0;
    }
    
    #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
    ", max);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件
    fstab文件详解
    Struts2与Spring的Maven依赖冲突
    maven正确的集成命令-U -B 等
    CentOS6安装Jenkins
    CentOS6下Jenkins连接Git服务器出错的问题
    GitLab备份的创建与恢复
    开发App到上架应用市场需要经历什么?
    阅读笔记:A Few useful things to Know About machine Learning
    Feature Tools 简介
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/5518817.html
Copyright © 2011-2022 走看看