算法竞赛入门经典 习题6-6

本文介绍了一个树形天平平衡问题的解决方法,采用递归思想从叶节点开始计算,优化过程中考虑了砝码权重的频次,实现了快速寻找最少修改砝码数量的算法。

UVa12166

Equilibrium Mobile

求出使得树形天平平衡需要修改的最小砝码的个数。

最开始我想到了这样一个递归方式:对于每一个节点

  • 使得左子树平衡,然后调整右子树和左子树的重量一样
  • 使得右子树平衡,然后调整左子树和右子树的重量一样

但是没有办法通过搜索来实现,因为在搜索算法中,递归到最深层就已经得到可行解了,然后慢慢地回退,再去拓展其它的解,而这道题在递归到最深层时时没有可行解的。

顺着这个思路想想,当递归到叶节点时,就可以固定这个砝码的重量,然后去调整其余所有砝码的总量,最终肯定是可以达到平衡的。

所以应该从叶节点开始,求出固定这个叶节点后使得天平平衡需要修改的砝码个数,思路为从叶节点开始向根迭代,每迭代一层,就要计算平衡这个子树需要修改的砝码数量。当迭代到根时,根据天平总重量计算平衡另一棵子树需要修改的砝码数量。提交了一版,超时了。

接下来要想想该怎么优化。上面的思路简单来说就是每一个砝码的重量都对应一个天平的总重量,如果多个砝码对应相同的重量,那么只需要修改剩余砝码不就可以了吗?

想到这里就更简单了,只需要根据叶节点的深度depth求出天平总重量,并统计总重量TotalWeight的频次,频次最大的那个就表示有多个砝码可以使得天平达到这个重量,那么只需要修改剩下的砝码就好了。

我本以为砝码只能是整数,原来还可以是浮点数。

#include <iostream>
#include <limits>
#include <map>
#include <string>

using namespace std;

class Solution
{
public:
	Solution(const string &expr)
	{
		size_t depth = 0;
		for(size_t i = 0 ; i < expr.length(); i++)
		{
			if (expr[i] == '[') depth++;
			else if (expr[i] == ']') depth--;
			else if (expr[i] == ',') continue;
			else {
				string value;
				while (isdigit(expr[i])) {
					value.push_back(expr[i++]);
				}
				unsigned long long TotalWeight = stoull(value) * (1ULL << depth);
				freq[TotalWeight]++;
				i--;
			}
		}
	}
	int FindMinChanges()
	{
		size_t leaves = 0;
		size_t MaxFreq = numeric_limits<size_t>::min();
		for (auto iter = freq.begin(); iter != freq.end(); iter++)
		{
			leaves += iter->second;
			if (iter->second > MaxFreq) {
				MaxFreq = iter->second;
			}
		}
		return leaves - MaxFreq;
	}
private:
	map<unsigned long long, size_t> freq;
};

int main()
{
	int cases = 0;
	cin >> cases;
	cin.get();
	for (int c = 0; c < cases; c++)
	{
		string expr;
		cin >> expr;
		Solution soluton(expr);
		cout << soluton.FindMinChanges() << endl;
	}
	return 0;
}
/*
3
[[3,7],6]
40
[[2,3],[4,5]]
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值