Dropping Balls(二叉树)

题目链接:

Online Judgeicon-default.png?t=LA46https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=620

 思路:

1.暴力模拟:开关只有两种状态,所以可以用二进制数组模拟所有开关的状态,进而模拟每个球的下落过程(但是由于时间复杂度达到O(N*2^N,会tle)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <string.h>
#include <climits>
#include <map>
#include <stack>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxd = 20; // 球的最大数量
// 1 << maxd表示2^maxd,而二叉树结构有2^maxd-1个点,这个数组用二进制表示开关状态
int swi[1 << maxd]; 

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int N; cin >> N;
    int D, I; // 树的深度,小球数量
    for(int i=0; i<N; i++){ // 实际上要处理N+1次输入,最后一次是-1
        cin >> D >> I;

        memset(swi, 0, sizeof(swi)); // 开始时所有开关关闭
        int k; // 当前节点位置
        int n = (1 << D) - 1; // 节点数量,用来进行越界判断
        while(I--){
            k = 1; // 从第一个节点开始
            for(;;){
                swi[k] = !swi[k]; // 二进制位取反
                k = swi[k] ? 2*k : 2*k+1; // 判断走的方向
                if(k > n) break; // 出界
            }
        }
        k /= 2; //返回子节点
        cout << k << endl;
    }
    cin >> D; // 处理最后输入的-1
    return 0;
}

 2.思考当前小球应该往哪边走。对于任意一个开关,假如当前小球是到这里的第N个球,分两种情况考虑:

a. N是奇数,那么前N-1个球一半走左边,一半走右边,当前球必定走左边,并且它是左边开关遇到的第(N-1)/2 + 1 = (N+1)/2个球。

b. N是偶数,那么前N-1个球中N/2个走左边,N/2-1个走右边(如果不懂可以自己找几个特殊例子算一下),当前球走右边,并且是右边开关遇到的第N/2个球。

有了这个想法,我么就可以迭代地算出当前球完整的行进路线了。

ac代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <string.h>
#include <climits>
#include <map>
#include <stack>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxd = 20; // 球的最大数量

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int N;
    cin >> N;
    int D, I;
    for(int i=0; i<N; i++){
        cin >> D >> I;
        int k = 1; // 当前位置
        for(int i=0; i<D-1; i++){ // 这里换一种判断出界的方式:小球必定下落D-1次
            if(I % 2 == 1){
                k = 2*k; //I是奇数,走左边
                I = (I + 1)/2; // 是左边开关的第(I+1)/2个球
            } else {
                k = 2*k + 1;
                I = I / 2;
            }
        }
        cout << k << endl;
    }
    cin >> D; // 处理最后-1的输入
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值