题意:给一个深度不超过16的二叉树,代表一个天平。 每根杆都悬挂在中间,每个秤砣的重量已知。 至少修改多少个秤砣的重量才能让天平平衡?
思路:
要想使整个二叉树平衡,二叉树的每个结点的值都可以算出一个值,即为整个二叉树的总重量:结点值*2^深度
这样,我们可以将所有结点值对应的总重量都算出来,看出现总重量重复次数最多的即要将此重量作为平衡的标准,
那么,将那些不遵循标准的结点值都改变即为最少即:总结点个数 - 总重量重复次数最多
(1)递归建树,建树时按“,”分别进行左右递归建树。以“[”为起点,当遇到一个"]"再进行递归,当然用一个标记值标记是递归层数,因为有可能出现“[[[[5,4]]]...]”,它是一个由外向里递归的过程,所有将不能一遇到“]”就进行递归,用标记值进行和“[”匹配才行,这里利用“[” :flag++, “]”:flag--,当flag==0时匹配成功!
(2)当递归到当前是结点值时,进行计算得出当前值,然后利用map集合进行累计总重量出现次数。map<long long,int> 键:总重量 ,值:出现次数
然后每次将次数最大保留。
(3)最后用总结点数 - max(总重量次数) 即为最少修改
参考:点击打开链接
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;
map<long long,int>cnt;//存放天平重量的次数
string str;
int num,maxn;
void dfs(int depth,int s,int e){//depth:树的深度,s:起始位,e:末尾位
int flag = 0;//用于计算一个完整的"[]"
if(str[s] == '['){//当遇到"["时,说明需要再找,还没有到达一个值
for(int i=s+1;i<=e;i++){
if(str[i] =='[') flag++;//当为‘[’时,计数加1,为寻找一个“[]”作准备
if(str[i] == ']') flag--;//
if(str[i] == ',' && flag == 0){//当遇到一个“,”时,并且flag=0:说明前面是一层树“[]”,或者是一个节点即单个数字
dfs(depth+1,s+1,i-1);//截取“,”之前的树再进行递归
dfs(depth+1,i+1,e-1);//截取“,”之后的树再进行递归
}
}
}else{//说明当前是一个数字,即结点
long long sum = 0;
for(int i=s;i<=e;i++) sum = sum * 10 + str[i]-'0';//计算当前结点的值
num++;//累计共有多少个结点
++cnt[sum<<depth];//将当前结点计算的总重量进行累计
maxn = max(maxn,cnt[sum<<depth]);//寻找出现最多次的重量
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
while(n--){
cin >> str;
num = 0;maxn = 0;cnt.clear();
dfs(0,0,str.length()-1);
printf("%d\n",num-maxn);//总结点-出现最多次的重量数,即为改变结点最少!
}
}
return 0;
}