记录一个很美妙的题目:UVA 12166

转载:https://blog.csdn.net/crazysillynerd/article/details/43876123

时间限制:3.000秒

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=3318

  脑子还是不够灵活,参考了别人的题解才绕过弯来,然后恍然大悟……

  给出数个天平,每个天平的结构都类似于二叉树,只有左右重量都相等时才平衡,求每个天平最少改多少个秤砣,也就是叶子结点可以使得整个天平平衡。天平的深度不超过16。

  要使得改动的数量最少,那么就至少有一个秤砣不变,然后以这个秤砣为基准来调整整个天平。天平的结构是二叉树,那么由此我们可以得出,如果以深度为d重量为w的秤砣为基准,那么整个天平的重量就是w * pow(2, d),即w << d。

  当然,可能会有一些秤砣算出的以各自为基准的天平总重量相同,设天平总重量为sumw,那么这些秤砣的数量就表示了如果使天平的总重量为sumw需要使多少个秤砣保持不变。

  基于上面的想法,就可以得到算法了。求出所有可能的sumw值以及其对应的秤砣数量,然后在这些sumw值中找到保持不变的秤砣数量中的最大值,设为maxn,设秤砣总数量为sum。那么sum - maxn即为所求。

  为了求出sumw对应的秤砣数量,这里用到了STL里的map结构,设为base,那么base[x]表示使天平的重量为x时保持不变的秤砣的数量。在建树时,每当扫描到叶子结点,即秤砣时,算出对应的sumw值,然后另base[sumw]自增1,这样所有的叶子节点都扫完之后,所有可能的sumw值也就算完了。接下来就只需要遍历一遍,找出最大值即可了。

    #include   
    #include   
    #include   
    #include   
    #include   

    using namespace std;  

    string line;  
    map base;  
    int sum;  

    void dfs(int depth, int s ,int e) {  
        if(line[s] == '[') {  
            int p = 0;  
            for(int i = s + 1; i != e; ++i) {  
                if(line[i] == '[') ++p;  
                if(line[i] == ']') --p;  
                if(p == 0 && line[i] == ',') {  
                    dfs(depth + 1, s + 1, i - 1);  
                    dfs(depth + 1, i + 1, e - 1);  
                }  
            }  
        } else {  
            long long w = 0;  
            for(int i = s; i <= e; ++i) w = w * 10 + line[i] - '0';  
            ++sum, ++base[w << depth];  
        }  
    }  

    int main() {  
        ios::sync_with_stdio(false);  
        int T;  
        cin >> T;  
        while(T--) {  
            cin >> line;  
            base.clear();  
            sum = 0;  
            dfs(0, 0, line.size() - 1);  

            int maxn = 0;  
            for(auto it = base.begin(); it != base.end(); ++it) maxn = max(maxn, it->second);  

            cout << sum - maxn << endl;  
        }  
    }  

这位博主写的代码太美妙了!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值