1. 程式人生 > >Hduoj2527【哈夫曼樹】

Hduoj2527【哈夫曼樹】

/*Safe Or Unsafe 
Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 9   Accepted Submission(s) : 5
Problem Description
Javac++ 一天在看計算機的書籍的時候,看到了一個有趣的東西!每一串字元都可以被編碼成一些數字來儲存資訊,但是不同的編碼方式得到的
儲存空間是不一樣的!並且當儲存空間大於一定的值的時候是不安全的!所以Javac++ 就想是否有一種方式是可以得到字元編碼最小的空間值!
顯然這是可以的,因為書上有這一塊內容--哈夫曼編碼(Huffman Coding);一個字母的權值等於該字母在字串中出現的頻率。所以Javac++ 
想讓你幫忙,給你安全數值和一串字串,並讓你判斷這個字串是否是安全的?
 
Input
輸入有多組case,首先是一個數字n表示有n組資料,然後每一組資料是有一個數值m(integer),和一串字串沒有空格只有包含小寫字母組成!
 
Output
如果字串的編碼值小於等於給定的值則輸出yes,否則輸出no。
 
Sample Input
2
12
helloworld
66
ithinkyoucandoit
 
Sample Output
no
yes

Source
HDU 2008-10 Programming Contest
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char s[10000010];
int mark[27], n, m;
int cmp(const void *a, const void*b)
{
	return *(int *)a - *(int *)b;
}
void sort(int x)
{
	int i, j, k;
	k = mark[x];
	for(i = x+1; i < 26; ++i)
	{
		if(mark[i] >= k)
		{
			for(j = x; j < i; ++j)
			mark[j] = mark[j+1];
			mark[i] = k;
			return ;
		}
	}
	for(j = x; j < 25; ++j)
	mark[j] = mark[j+1];
	mark[25] = k;
}
int main()
{
	int i, j, k, t, ans;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d", &n);
		getchar();
		gets(s);
		m = strlen(s);
		memset(mark, 0, sizeof(mark));
		ans = 0;
		for(i = 0; i < m; ++i)
		mark[s[i] - 'a']++;
		qsort(mark, 26, sizeof(mark[0]), cmp);
		for(i = 0; i < 26; ++i)
		{
			if(mark[i] != 0)
			{
				for(j = i; j < 26; ++j)
				{
					mark[j+1] += mark[j];
					ans += mark[j+1];
					sort(j+1);
				}
				if(ans != mark[26])//處理當只有一種字元時的情況 
				ans -= mark[26];
				break;
			}
		}
		if(ans <= n)
		printf("yes\n");
		else
		printf("no\n");
	}
	return 0;
}

題意:給出一個字串,字串中的每種字母都有一個權值,其權值即為它在字串中出現的頻率,現在要求將每種字母的權值作為一個節點進行哈夫曼樹的構造,算出樹的權值是否小於等於安全值,若是輸出yes,否則no。

思路:此題考查的就是對哈夫曼樹的理解,剛開始忘了哈夫曼樹的權值怎麼算的了。。。一直錯,所以一定要對哈夫曼樹的定義非常清楚,樹的權值就是非葉子節點的總和,所以我這裡用貪心去做,即先對所有權值進行升序排序,每次從陣列中取出2個最小的值相加,那麼加出來的這個數肯定是非葉子節點加入ans中,其次加完之後將陣列中前一個數直接遺棄,對於新加出來的數則作為加數的後一個,即陣列中的後一個數,然後對該數進行排序插入操作,為的就是保證陣列中前2個數一定是陣列中所剩餘的數是按升序排列的,然後只要一直加到底,並且每次都把加出來的和加入ans中即可,ans即為哈夫曼樹的權值。其次我這裡為了處理當字串中只有一種字母的情況,將加數多擴了一位並且置零,若是隻有一種字母,那麼ans肯定等於陣列中的最後一位,若不止一種字母,那麼ans必定不等於陣列中的最後一位。