UVA 679 小球掉落 思维 + 数据结构

题目大意:

  有一棵二叉树, 最大深度为D, 且所有叶子的深度都相同, 所有节点从上到下,从左到右编号依次为, 0, 1, 2, ....(2^n)-1,从节点1开始放球, 每个节点有一个开关, 开关关时向左 ,否则向右, 小球的每次撞击会使开关的状态改变。

  这是一道很蠢的题, 一个简单的模拟就会输出答案:

  

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

const int maxd = 20;
int s[1 << maxd];

int main() {
    int D, I;
    while( ~scanf( "%d%d", &D, &I ) ) {
        memset( s, 0, sizeof( s ) );
        int k = 0;
        int n = ( 1 << D ) - 1;
        for( int i = 0; i < I; i++ ) {
            k = 1;
            while( 1 ) {
                s[k] = !s[k];
                k = s[k] ? k * 2 : k * 2 + 1;
                if( k > n ) break;
            }
        }
        printf( "%d\n", k / 2 );
    }
    return 0;
}
View Code

 

  但是时间会超。

 

  所以不知道哪一位大佬, 很聪明的发现:

  单对于第一个小球来说, 会一直向左走( 因为初始状态下, 开关全部关闭 ), 对于第二个小球来说会落到右子树的最左节点( 因为第一个球将根节点的开关状态改变 ), 同理第三球会落到左子树的右子树的最左节点......

  所以发现规律:

  当最后一个球为奇数的时候会走到左子树, 这时将左子树的第一个节点当做根节点, 迭代下去直到当前的深度deep超过给定的深度D

  思维题。

  哪一道题都需要自己仔细的斟酌。

  

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

int main() {
    int d, i;
    while( ~scanf( "%d%d", &d, &i) ) {
        int ans = 1;
        int deep = 1;
        while( deep < d ) {
            if( i & 1 ) {
                ans *= 2;
                i = ( i + 1 ) / 2;
            }
            else {
                ans = ans * 2 + 1;
                i /= 2;
            }
            deep++;
        }
        printf( "%d\n", ans );
    }
    return 0;
}
View Code

  

  坚持早起已经一周多了, 感觉还不错, 另外一会儿把周日那场组队赛的题单的博客写了。

  多练思维 ,算法只是辅助的工具, 怒整动态规划! 

  

posted on 2016-10-25 16:22  FriskyPuppy  阅读(460)  评论(0编辑  收藏  举报

导航