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(二叉树的编号)的主要内容,如果未能解决你的问题,请参考以下文章

小球下落 (Dropping Balls,UVA 679)

UVa 679 Dropping Balls (例题 6-6)

Dropping Balls UVA - 679(二叉树的遍历)

Uva679 Dropping Balls

UVa 679 - Dropping Balls二叉树思维题

UVA 679 - Dropping Balls