Uva 12166 严格平衡树

原题

一开始想得太简单, 直接读数据建立树, 然后像堆调整那样一个个结点检查并向上调整子节点的重量, 后来写到一半发现这样不可行, 需要处理的情况太多, 这样模拟的过程太繁琐了..
于是可耻地google了答案——原来这棵树每层的结点值都是满足一定规律的,在同一层上的结点值必须相等, 而且上层的值是下一层的节点值的两倍。

认识到这个规律后,还是需要做一点巧妙的处理(方法来自这里 ) :

由于只要选择一个叶节点作为标准就可以确定一棵树的总重量,
因此遍历每个叶节点, 确定以其作为标准时树的总重量,
那么最多叶节点对应的那个总重量就是树应该取的最终总重量 M,
用总的叶结点数减去M所对应的叶节点数即可得到需要改变的叶节点数.

还有一个需要注意的地方就是由于结点的值正好压了int的范围, 所以树的总重量肯定有可能超过int, 因此要用 long long 来存储树的总重量

以下为模仿答案写的代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <list>
#include <cassert>
#include <iomanip>

#pragma warning(disable:4996) //关掉4996警告

/*
Uva 439
关键 :  1. 事先找出规律!!!
        2. 技巧 : 由于只要选择一个叶节点作为标准就可以确定一棵树的总重量,
        因此遍历每个叶节点, 确定以其作为标准时树的总重量, 那么
        最多叶节点对应的那个总重量就是树应该取的最终总重量 M,
        用总的叶结点数减去M所对应的叶节点数即可得到需要改变的叶节点数
*/

using namespace std;

int Leaves;

string input;
int ptr;

map<long long, int> WeightNum;      // 记录树的某个总重量所对应的标准结点数

void Build(int Depth) {
    char ch;
    ch = input[ptr++];
    if ( ch == '[' ) {
        Build(Depth+1);
        ch = input[ptr++];          // 读 ','
        Build(Depth+1);
        ch = input[ptr++];          // 读 ']'
    }else {                         // 找到一个叶节点
        long long sum = 0;
        do {
            sum = sum * 10 + ch - '0';
            ch = input[ptr++];
        } while ( ptr < input.size() && ch != ',' && ch != ']' );
        ptr--;
        WeightNum[sum << Depth]++;
        Leaves++;
    }
    return;
}


int main( ) {
    //freopen("input.txt", "r", stdin);
    int N;
    cin >> N;
    for ( int i = 0; i < N; i++ ) {
        WeightNum.clear( );
        cin >> input;
        Leaves = ptr = 0;
        Build(0);
        int mostNum = 0;
        for ( auto it = WeightNum.begin( ); it != WeightNum.end(); it++ ) {
            mostNum = max(mostNum, it->second);
        }
        cout << Leaves - mostNum << endl;
    }

    //system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值