#221. 抢气球

8 篇文章 2 订阅
这篇博客介绍了如何解决一个公平分配气球给不同高度小朋友的问题。通过使用归并排序和二分查找算法,确保每个小朋友按跳得低到高的顺序摘取他们能触及的气球。算法首先对小朋友的高度和气球的高度进行排序,然后通过二分查找确定每个小朋友能摘到的气球数量。博客详细展示了C++代码实现,并提供了样例输入和输出。
摘要由CSDN通过智能技术生成

题目描述

​ 教室的墙上挂满了气球,五颜六色,小朋友们非常喜欢。

​ 刚一下课,小朋友们就打算去抢这些气球。每个气球在墙上都有一定的高度,只有当小朋友跳起来时,手能够到的高度大于等于气球的高度,小朋友才能摘到这个气球。为了公平起见,老师让跳的低的小朋友先摘,跳的高的小朋友后摘。小朋友都很贪心,每个小朋友在摘气球的时候都会把自己能摘的气球都摘掉。

​ 很巧的是,小朋友们跳起来手能够着的高度都不一样,这样就不会有跳起来后高度相同的小朋友之间发生争执了。

输入
​ 第一行输入两个空格分隔的整数 n,m(1≤n,m≤100000) ,其中 n 表示小朋友的数量,m 表示墙上气球的数量。

​ 第二行输入 n 个正整数(每两个整数之间用空格隔开),第 i 个数为 ai(1≤ai≤109),表示第 i 个小朋友跳起来手能够着的高度为 ai 。

​ 第三行输入 m 个正整数(每两个整数之间用空格隔开),第 i 个数为hi ,表示第 i 个气球的高度为 hi。

输出
​ 输出一共 n 行,每行一个整数。​ 第i 行表示第 i​ 个小朋友摘到的气球数量。

样例输入

5 6
3 7 9 6 4
1 2 3 4 5 6

样例输出

3
0
0
2
1

解决方案

#include <stdio.h>
#define swap(a,b){__typeof(a) __tmp=a;a=b;b=__tmp;}
//利用归并排索引
void merge(int *nums,int start,int end,int * ans){
	if(start>=end) return;
	int mid=(start+end)>>1;
	merge(nums,start,mid,ans);
	merge(nums,mid+1,end,ans);
	int i=start,j=mid+1,k=0;
	int * tmp=(int *)malloc(sizeof(int)*(end-start+1));
	while(i<=mid||j<=end){
		if(j>end||i<=mid && nums[ans[i]]<=nums[ans[j]]){
			tmp[k++]=ans[i++];
		}else{
			tmp[k++]=ans[j++];
		}
	}
	
	memcpy(ans+start,tmp,sizeof(int)*k);
	free(tmp);
}
	
//利用快排得到气球高度
void quick_sort(int *nums,int start,int end){
	if(start>=end) return;
	int i=start,j=end,mid=nums[(start+end)>>1];
	while(i<=j){
		while(i<=j&&nums[i]<mid) i++;
		while(i<=j&&nums[j]>mid) j--;
		if(i<=j){
			swap(nums[i],nums[j]);
			i++;j--;
		}
	}
	quick_sort(nums,start,j);
	quick_sort(nums,i,end);
}
	
//二分查找右边界,找到第一个大于val的值
int bin_serach(int *nums,int size,int val){
	int left=0,right=size;
	while(left<right){
		int mid=(left+right)>>1;
		if(nums[mid]<=val) left=mid+1;
		else right=mid;			
	}
	return left;
}	

// 以以下数据为例
//3 7 9 6 4
//1 2 3 4 5 6	
int main(){
	int m,n;
	scanf("%d%d",&m,&n);
	int * arr1=(int *)malloc(sizeof(int)*m); //存储孩子能够到的最大高度 3 7 9 6 4
	int * arr1_idx=(int *)malloc(sizeof(int)*m); //存储arr1排序后的索引 0 4 3 1 2
	int * ans=(int *)malloc(sizeof(int)*m); //存储最终结果 
	memset(ans,0,sizeof(int)*m);
	for(int i=0;i<m;i++){
		scanf("%d",&arr1[i]);
		arr1_idx[i]=i;
	}
	int * arr2=(int *)malloc(sizeof(int)*n); //存储气球高度 1 2 3 4 5 6
	for(int i=0;i<n;i++){
		scanf("%d",&arr2[i]);
	}
	//从小到大排序
	merge(arr1,0,m-1,arr1_idx);
	quick_sort(arr2,0,n-1);
	 //存储前面的值,比如第一次:0号孩子能够到的高度为3,它在arr2的左边界为3(arr1[arr1_idx[0]]),第二个孩子能够到的高度为4,左边界为4,他能摘的气球需要减去前面的3,即为1;
	int sum=0;
	for(int i=0;i<m;i++){
		if(sum==n) break;//当前面孩子摘满了,后面无需在判断,直接为默认的0即可;
		int val=arr1[arr1_idx[i]]; //arr1从小到大排序,需要寻找的值
		int idx=bin_serach(arr2,n,val); // 到第一个大于val的值的索引
		ans[arr1_idx[i]]=idx-sum;	
		sum+=ans[arr1_idx[i]];		
	}
	
	for(int i=0;i<m;i++){
		printf("%d\n",ans[i]);
	}
	
	//释放malloc申请的空间
	free(arr1);
	free(arr1_idx);
	free(arr2);
	free(ans);
	
	return 0;
}

在这里插入图片描述

小结

关键在于排索引,数据规模较大时,考虑快排或者归并,快排可能改变两个相等量的相对顺序(不稳定),归并则不会

好的,我会设计一个基类为飞行器(Aircraft),然后派生出子类飞机(Airplane)、鸟(Bird)、火箭(Rocket)和热气球(HotAirBalloon)。每个类都会有自己独特的飞行行为。 首先,我们定义基类飞行器(Aircraft): ```python class Aircraft: def fly(self): pass ``` 然后,我们定义子类飞机(Airplane),它具有发动机(Engine): ```python class Engine: def start(self): pass def stop(self): pass class Airplane(Aircraft): def __init__(self): self.engine = Engine() def fly(self): self.engine.start() print("飞机起飞") # 其他飞行代码 self.engine.stop() print("飞机降落") ``` 接下来,定义子类鸟(Bird),它具有翅膀(Wing): ```python class Wing: def flap(self): pass class Bird(Aircraft): def __init__(self): self.wing = Wing() def fly(self): self.wing.flap() print("鸟儿飞翔") # 其他飞行代码 ``` 然后,定义子类火箭(Rocket),它使用空气动力: ```python class Rocket(Aircraft): def fly(self): print("火箭发射") # 其他飞行代码 ``` 最后,定义子类热气球(HotAirBalloon),它使用氢气: ```python class HotAirBalloon(Aircraft): def fly(self): print("热气球升空") # 其他飞行代码 ``` 现在,我们可以演示各种飞行行为: ```python # 创建飞机对象 airplane = Airplane() # 飞机起飞和降落 airplane.fly() # 创建鸟对象 bird = Bird() # 鸟儿飞翔 bird.fly() # 创建火箭对象 rocket = Rocket() # 火箭发射 rocket.fly() # 创建热气球对象 hot_air_balloon = HotAirBalloon() # 热气球升空 hot_air_balloon.fly() ``` 这样,通过多态,每个飞行器对象都可以调用相应的飞行方法,展示各自的飞行行为。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值