算法思想:
给出一串字符串,和一个安全数值,字母出现的频率等于该字符的权重。
建立哈夫曼树,计算带权路径长,带权路径长小于等于安全数值输出yes
否则输出no。
代码如下:
#include<iostream>
using namespace std;
struct HuffmanTree
{
int weight;
int parent, lchild, rchild;
};
void Select(HuffmanTree *HT, int a, int& s1, int& s2)
{
for (int i = 1; i <= a; i++)
{
if (!HT[i].parent)
{
s1 = i;
break;
}
}
for (int i = 1; i <= a; i++)
{
if ((!HT[i].parent) && (i != s1))
{
s2 = i;
break;
}
}
for (int i = 1; i <= a; i++)
{
if (HT[i].weight < HT[s1].weight && !HT[i].parent && (s2 != i))
{
s1 = i;
}
}
for (int i = 1; i <= a; i++)
{
if (HT[i].weight < HT[s2].weight && !HT[i].parent && (s1 != i))
{
s2 = i;
}
}
}
void CreatHuffmanTree(HuffmanTree*& HT, int n,int *num)//哈夫曼树初始化
{
if (n <= 1)return;
int m = 2 * n - 1;
HT = new HuffmanTree[m + 1];
for (int i = 1; i <= m ; ++i)
{
HT[i].lchild = 0;
HT[i].rchild = 0;
HT[i].parent = 0;
HT[i].weight = 0;
}
for (int i = 1; i < n + 1; ++i) HT[i].weight = num[i-1];
int s1, s2;
for (int i = n + 1; i <= m; ++i)
{
Select(HT, i - 1, s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
}
int d = 0;
int wpl = 0;//定义全局变量,因为static知道程序结束才会销毁
int WPL(HuffmanTree* HT, int a)//计算带权路径
{
int temp = 0;//表示该节点的d ,防止递归增加d
d++;
if (HT[a].lchild == 0 && HT[a].rchild == 0)//为叶子结点返回权乘以路径长
{
return wpl = wpl + (d - 1) * HT[a].weight;
}
else
{
temp = d;//存储该节点的d
WPL(HT, HT[a].lchild);
if (HT[a].lchild != 0 || HT[a].rchild != 0) d = temp;//递归一次后d加一,但temp为该节点的d
WPL(HT, HT[a].rchild);
}
}
int main()
{
int n;
cin >> n;
while (n--)
{
int safeNum;//安全数值
string word;//字符串
int* k = new int[26];//字母的权的数组
int x = 0;//用来表示k的元素的个数
cin >> safeNum;
cin >> word;
for (int i = 'a'; i < 'z' + 1; i++)//求字母的权
{
int rate = 0;//该字母出现的次数
char temp;
for (int j = 0; j < word.size(); j++)
{
temp = (char)i;
if (temp == word[j])
{
rate++;
}
}
if(rate!=0)//rate为0证明没有这个字母
k[x++] = rate;
}
HuffmanTree* HT;
CreatHuffmanTree(HT, x,k);//哈夫曼树初始化
int a;//表示哈夫曼树根结点的数组下标
for (int i = 1; i <= 2 * x - 1; i++)
{
if (HT[i].parent == 0)
{
a = i;
break;
}
}
int w = WPL(HT, a);//计算带权路径
if (w > safeNum)cout << "no"<<endl;//和安全数值比较
else cout << "yes"<<endl;
d = 0;
wpl = 0;//将静态变量从新赋值
}
return 0;
}