6_6小球下落uva679(刷题笔记)

本文介绍了如何解决UVA679题目中的小球下落问题,原始方法通过暴力模拟导致效率低下,随后提出通过观察小球编号的奇偶性优化算法,减少对数组的重置,提高了处理大数据的能力。
摘要由CSDN通过智能技术生成

6_6小球下落uva679(刷题笔记)

题目

洛谷题目连接

在这里插入图片描述

在这里插入图片描述

思考

  • 观察树可得,对于任意一个非叶子节点k,其左节点、右节点分别为2k和2k+1。
  • 每个一个节点都有一个标记false或true,很容易想到使用一个数组tree[]存储每个节点的标记。

暴力模拟

#include<cstdio>
#include<cstring>
using namespace std;

bool tree[600000];//标记数组

int main(){
	int T,D,I,p;//T数据组数;D树深度,I掉落小球编号,p为节点编号
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&D,&I);
		
		//模拟编号为1~i小球掉落
		for(int i = 1;i<=I;i++){
			
			p = 1;//每个小球每次从头开始掉落
			
			//暴力模拟每个小球掉落过程,掉落层数为d-1次
			for(int k = 1;k<D;k++){
				if(!tree[p])tree[p] = true,p = p*2;
				else tree[p] = false,p=p*2+1;
			}
		}
		printf("%d\n",p);//输出叶子节点
		memset(tree,false,sizeof(tree));//重置
	}
	scanf("%d",&T);//输入-1
	return 0;
}

算法优化

以上算法每一次模拟小球掉落后,都要对tree[]数组进行重置,这对于大数据的测试数据来说数据量太大。

观察运行结果,其实每一步小球的行走路径是可以通过小球编号的奇偶性判断,如2号球经过第一个节点时,由于1号球改变了该节点的状态为true,所以2号球必定往右孩子方向走。
由此可推出:

  • 任何一个奇数编号球I=2k+1,在经过某个节点的时候,它一定是第(I+1)/2个经过该节点的编号球;
  • 任何一个偶数编号球I=2k,在经过某个节点的时候,它一定是第I/2个经过该节点的编号球。
    所以只要知道一个球是第几个经过该节点的球,就可以依次递推。
#include<cstdio>
#include<cstring>
using namespace std;

bool tree[600000];//标记节点

int main(){
	int T,D,I,p;//T数据组数;D树深度,I掉落小球编号
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&D,&I);
		int k = 1;
		
		//直接模拟该小球的掉落路径即可,不需要将前面的所有小球都模拟一遍
		for(int i = 1;i<D;i++){
			if(I%2){//小球编号为奇数时,走左孩子
				k = k*2;
				I = (I+1)/2;//它是第(I+1)/2个经过左孩子的球
			}else{//小球编号为偶数时,走右孩子
				k = k*2+1;
				I = I/2;//它是第I/2个经过该右孩子的球
			}
		}
		printf("%d\n",k);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值