uva12166

原题:
A mobile is a type of kinetic sculpture constructed to take advantage of the principle of equilibrium. It con-
sists 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 10^9 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.
Sample Input
3
[[3,7],6]
40
[[2,3],[4,5]]
Sample Output
1
0
3

中文:
给你一个二叉树形式的天平,每个二叉树的叶子节点上有一个砝码,现在为了使二叉树平衡,需要修改部分砝码值,最少修改多少砝码值可以使二叉树平衡?

代码:

#include<iostream>
#include<string>
#include<stack>
#include<map>
#include<algorithm>
#include<cstdlib>
#include<fstream>
using namespace std;
typedef long long ll;
const int maxn = 200001;
int t;
string s;

map<ll, int> weight;


//fstream in("in.txt");
//fstream out("out.txt");


void solve()
{
	
	stack<char> sc, num;
	int cnt = 0;
	weight.clear();
	for (int i = 0; i<s.size(); i++)
	{
		if (s[i] == '[')
		{
			sc.push('[');
			continue;

		}
		if (s[i] >= '0'&&s[i] <= '9')
		{
			num.push(s[i]);
			continue;
		}
		if (s[i] == ',')
		{
			if (num.empty())
				continue;

			
			ll dep = sc.size();
			ll j = 1, tmp = 0;
			while (!num.empty())
			{
				tmp += (num.top() - '0')*j;
				num.pop();
				j *= 10;
			}
			++weight[tmp << dep];
			cnt++;
			continue;
		}
		if (s[i] == ']')
		{
			if (num.empty())
			{
				sc.pop();
				continue;
			}
			ll j = 1, tmp = 0;

			while (!num.empty())
			{
				tmp += (num.top() - '0')*j;
				num.pop();
				j *= 10;
			}

			ll dep = sc.size();
			++weight[tmp << dep];
			cnt++;
			sc.pop();
			continue;
		}
	}
	int ans = 0;
	for (auto w : weight)
	{
		ans = max(ans, w.second);
	}
	cout << cnt - ans << endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin >> t;
	while (t--)
	{
		cin >> s;

		solve();

	}
	//in.close();
	//out.close();
	//system("pause");
	return 0;
}

解答:

紫书上的习题
这题印象很深刻,上学的时候学数据结构的时候照着书上题目列表顺序做,做到这题卡住了。当时先搁置,直到自己都工作了,才想起来它。当然,依旧没想出来怎么搞-_-|||

这道题自己在纸上画一画,如果能发现规律应该立刻就解决出来了,不过此题顶着个二叉树数据结构的标签,很容易让人联想到搜索或者树形dp之类的。基本上就想歪了,遇到问题应该先找一找问题的规律,找到关键点,很快问题就会迎刃而解。

参考博客

第一点,要发现从根出发到叶子节点上去寻找解,没有明确的决策过程可以寻找,因为改变左子树的非叶子节点值,必然需要改变其子孙节点值。此外,还需要将其兄弟节点的值改为与之相同。

第二点,并非一颗完全二叉树,无法通过非叶子节点的数值的奇偶性去寻找规律。

以上,也就是无法通过非叶子节点到叶子节点去寻找解。那么,只能从叶子节点向根节点寻找规律。
其实,只要任意一个叶子节点的值固定,由于平衡性,整棵树的所有值就都固定了。

如果某个叶子节点的值是w,深度是d,那么整棵树的质量就应该是w×2dw×2^d

所以,只需要枚举所有不同深度叶子节点出现过的值,将该值固定,其余的叶子节点的值也就固定下来,最终将总节点数减去同深度且同权值的叶子节点的个数就是以当前节点作为枚举值的最优解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章