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

所以,只需要枚舉所有不同深度葉子節點出現過的值,將該值固定,其餘的葉子節點的值也就固定下來,最終將總節點數減去同深度且同權值的葉子節點的個數就是以當前節點作爲枚舉值的最優解。

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