UVa12166 Equilibrium Mobile(思维+dfs建树)

题目链接

A mobile is a type of kinetic sculpture constructed to take advantage of the principle of equilibrium. It consists of a number of rods, from which weighted objects or further rods hang. The objects hanging from the rods balance each other, so that the rods remain more or less horizontal. Each rod hangs from only one string, which gives it freedom to rotate about the string. We consider mobiles where each rod is attached to its string exactly in the middle, as in the gure underneath. You are given such a conguration, but the weights on the ends are chosen incorrectly, so that the mobile is not in equilibrium. Since that’s not aesthetically pleasing, you decide to change some of the weights. What is the minimum number of weights that you must change in order to bring the mobile to equilibrium? You may substitute any weight by any (possibly non-integer) weight. For the mobile shown in the gure, equilibrium can be reached by changing the middle weight from 7 to 3, so only 1 weight needs to changed.

Input
On the rst line one positive number: the number of testcases, at most 100. After that per testcase:
• One line with the structure of the mobile, which is a recursively dened expression of the form:
< expr > ::= < weight > | “[” < expr > “,” < expr > “]”
with < weight > a positive integer smaller than 109 indicating a weight and ‘[< expr >,< expr >]’ indicating a rod with the two expressions at the ends of
the rod. The total number of rods in the chain from a weight to the top of the mobile will be at most 16.

Output
Per testcase:
• One line with the minimum number of weights that have to be changed.

1.这种题目真的很难下手,刚开始以为要由叶子节点一层层上去,逐一比较每层的大小关系确定修改哪一层。但是想着想着觉得好像没有那么简单,看着题目的输入,不知道到底是由’[’ ']‘确定层数还是由’,'确定层数。想了又想,真的不会,tcl

2.看了网上都是一个思路:因为天平下的左右部分严格对称,从最终状态倒推,那么已知根节点的重量,每次除以二就能得到左右两部分的重量,进而得到所有叶子节点的重量,而且同一层的叶子节点重量严格相等。我们假设其中一个在树的第d层的叶子节点重量w不修改,那么可以得到整棵树的总重量w*2d,简化为w<<d。那么由前面说的,可以得到每个节点的重量,第一时间就会想到再去求每个叶子节点的重量看看需要修改多少次。但是整棵树最多16层,最多216个叶子节点,显然这样肯定超时。这时最重要的思维来了,由于确定的叶子节点和确定的整棵树的重量是一一对应关系,那么我们直接去判断对于每一棵树的重量能对应多少个叶子节点不变(用map保存),那么最少的修改次数就是总的叶子节点数减去出现次数最多的树的重量(🐮🍺orz! %% )

3.可是,这种输入怎么求出每个节点的层数和总的叶子数呢?(又被卡住了,靓仔落泪)。看了好大一会才看懂LRJ是如何巧妙利用DFS建树:首先观察样例可以知道,凡是叶子节点有兄弟节点,那么二者就会被"[ ]"框起来,否则直接表示该叶子节点的值。那么我们可以利用二叉树的建树思想,由最外层的“[ ]”,一路走到中点,这个中点的确定非常巧妙,详细见代码。然后逐渐二分,层数加一,当区间内包含的是数字就求树的值并保存

代码:

#include <iostream>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
typedef long long ll;
map<ll,int> mp;  //因为求树的值会爆int所以用long long
string s;
int num,sum;  //分别表示最大的树重量和总的节点数量

void build(int l,int r,int d){
    if(s[l]=='['){
        int flag=0;     //表示接下来的一半叶子区间是否结束
        for(int i=l+1;i<=r;i++){
            if(s[i]=='[') flag++;
            if(s[i]==']') flag--;
            if(s[i]==',' && !flag){ //根据","和flag确定“中点”
                build(l+1,i-1,d+1);
                build(i+1,r-1,d+1);
            }
        }
    }else{ //当区间只剩数字字符时得到该树的值
        sum++;
        ll temp=0;
        for(int i=l;i<=r;i++)
            temp=temp*10+s[i]-'0';  //由字符串数字得到十进制数字
        int res = ++mp[temp<<d];  
        num=max(num,res);  //为了方便我们每次取当前得到的最大即可
    }
}


int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        cin>>s;
        mp.clear();   //不要忘了map的初始化
        sum=num=0;
        build(0,s.size()-1,0);
        printf("%d\n",sum-num);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值