Uva12166 Equilibrium Mobile 【递归建树】【习题6-6】

题目:Equilibrium Mobile

题意:给一个深度不超过16的二叉树,代表一个天平。 每根杆都悬挂在中间,每个秤砣的重量已知。 至少修改多少个秤砣的重量才能让天平平衡?

思路:

要想使整个二叉树平衡,二叉树的每个结点的值都可以算出一个值,即为整个二叉树的总重量:结点值*2^深度

这样,我们可以将所有结点值对应的总重量都算出来,看出现总重量重复次数最多的即要将此重量作为平衡的标准,

那么,将那些不遵循标准的结点值都改变即为最少即:总结点个数 - 总重量重复次数最多

(1)递归建树,建树时按“,”分别进行左右递归建树。以“[”为起点,当遇到一个"]"再进行递归,当然用一个标记值标记是递归层数,因为有可能出现“[[[[5,4]]]...]”,它是一个由外向里递归的过程,所有将不能一遇到“]”就进行递归,用标记值进行和“[”匹配才行,这里利用“[” :flag++,   “]”:flag--,当flag==0时匹配成功!

(2)当递归到当前是结点值时,进行计算得出当前值,然后利用map集合进行累计总重量出现次数。map<long long,int>  键:总重量  ,值:出现次数

然后每次将次数最大保留。

(3)最后用总结点数 - max(总重量次数) 即为最少修改

参考:点击打开链接

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;
map<long long,int>cnt;//存放天平重量的次数
string str;
int num,maxn;
void dfs(int depth,int s,int e){//depth:树的深度,s:起始位,e:末尾位
    int flag = 0;//用于计算一个完整的"[]"
    if(str[s] == '['){//当遇到"["时,说明需要再找,还没有到达一个值
        for(int i=s+1;i<=e;i++){
            if(str[i] =='[') flag++;//当为‘[’时,计数加1,为寻找一个“[]”作准备
            if(str[i] == ']') flag--;//
            if(str[i] == ',' && flag == 0){//当遇到一个“,”时,并且flag=0:说明前面是一层树“[]”,或者是一个节点即单个数字
                dfs(depth+1,s+1,i-1);//截取“,”之前的树再进行递归
                dfs(depth+1,i+1,e-1);//截取“,”之后的树再进行递归
            }
        }
    }else{//说明当前是一个数字,即结点
        long long sum = 0;
        for(int i=s;i<=e;i++) sum = sum * 10 + str[i]-'0';//计算当前结点的值
        num++;//累计共有多少个结点
        ++cnt[sum<<depth];//将当前结点计算的总重量进行累计
        maxn = max(maxn,cnt[sum<<depth]);//寻找出现最多次的重量
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        while(n--){
            cin >> str;
            num = 0;maxn = 0;cnt.clear();
            dfs(0,0,str.length()-1);
            printf("%d\n",num-maxn);//总结点-出现最多次的重量数,即为改变结点最少!
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值