Uva--679 Dropping Balls(二叉树的编号)
Posted 57one
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Uva--679 Dropping Balls(二叉树的编号)相关的知识,希望对你有一定的参考价值。
记录
23:28 2023-4-16
https://onlinejudge.org/external/6/679.pdf
reference:《算法竞赛入门经典第二版》例题6-6
二叉树,这里是完全二叉树,使用模拟的方式应该会TLE(虽然我用模拟的方式也TLE了,但不是这个原因,下面会提到原因)
不用模拟的方式,转换思路,使用递归的方式去思考。
这里是完全二叉树,使用数组模拟完全二叉树。
对于每个小球,肯定会经过根节点(先考虑D=1的时候的根节点)(在数组完全二叉树中位置为1),对于这个根节点来说,标号为奇数的小球肯定走左子树,为偶数的小球肯定走右子树。
对于走左子树的小球,此时把左边这个做为新的根节点(D=2,在数组完全二叉树中位置为2),继续对进入左边的小球进行判断,奇数继续走左子树,偶数继续走右子树。
小球编号 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
数组下标为1作为根 | 1(走1的左子树) | 1(走1的右子树) | 2(走1的左子树) | 2(走1的右子树) |
数组下标为2作为根 | 1(走2的左子树) | 2(走2的右子树) |
我TLE的原因是,书上和Uva网站上的题不是相同的。。输入就是有问题的。。还是要看原来的题的表述
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
#define MAX_N 20
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int INF = 0x3f3f3f3f;
int arr[1 << MAX_N];
int N, D, I;
void solve()
fill(arr, arr + (1 << MAX_N), 0);
int k = 1, n = (1 << D) - 1;
for(int i = 0; i < I; i++)
k = 1;
for(;;)
arr[k] = !arr[k];
k = arr[k]? 2 * k : 2 * k + 1;
if(k > n) break;
printf("%d\\n", k / 2);
void solve1()
int k = 1;
for(int i = 0; i < D-1; i++)
if(I % 2 == 1)
k = k * 2;
I = (I + 1) / 2;
else
k = k * 2 + 1;
I = I / 2;
printf("%d\\n", k);
//solve 会TLE
int main()
scanf("%d\\n", &N);
for(int i = 0; i < N; i++)
scanf("%d%d", &D, &I);
solve1();
// while (scanf("%d%d", &D, &I) == 2)
// solve1();
//
UVa OJ 679 - Dropping Balls
本题是一个二叉树问题——Perfect Binary Tree。
一个完美二叉树(PBT)的深度为D,从根结点开始,按层次遍历顺序编号为1,2,...,2D-1。
有若干个球,依次由根结点落下。当一个球落在非叶结点上时,将向左子树或右子树落下。这个方向由每一个结点的flag控制(其中,flag是一个0-1型变量):
①当flag==0时,小球向左子树运动;
②当flag==1时,小球向右子树运动。flag初始化为0。
一个小球路过该结点后,该结点的flag值变化。
求解第I个球最终到达的叶结点。
可以考虑模拟。直接模拟的时间复杂度为O(ID),空间复杂度为O(2D),多组数据下TLE。
值得注意的是,在题中的编号方式中,若一个结点的编号为k,则其左子结点的编号为2k,右子结点的编号为2k+1。
于是,可以考虑某一个结点k的情况:若某一个小球是第i个路过结点k的小球,则:
①当i为奇数时,小球向左,下一个结点为2k:此时,该小球是向左的第(i+1)/2个小球;
②当i为偶数时,小球向右,下一个结点为2k+1:此时,该小球是向右的第i/2个小球。
于是,可以直接模拟第I个球的路线。时间复杂度为O(D),空间复杂度为O(1)。
参考程序如下:
#include <stdio.h> int main(void) { int n, d, i; scanf("%d", &n); while (n--) { scanf("%d%d", &d, &i); int k = 1; d--; while (d--) { if (i & 1) { k = k << 1; i = i + 1 >> 1; } else { k = k << 1 | 1; i = i >> 1; } } printf("%d\n", k); } return 0; }
以上是关于Uva--679 Dropping Balls(二叉树的编号)的主要内容,如果未能解决你的问题,请参考以下文章
UVa 679 Dropping Balls (例题 6-6)
Dropping Balls UVA - 679(二叉树的遍历)