uva - 10954 - Add All(优先队列、哈夫曼编码思想)

题意:题目名称就是你要做的任务:把一些数加起来。但是这对你来说一定是太简单了,所以让我们加一些东西在里面。

做加法要付出的代价(cost) 定义为这2个数的总和,所以要加1 和10 所需付出的代价为11 。假如你想要加1, 2 和3,那么有以下几种方法:


1 + 2 = 3, cost = 3 
3 + 3 = 6, cost = 6 
Total = 9

1 + 3 = 4, cost = 4 
2 + 4 = 6, cost = 6 
Total = 10

2 + 3 = 5, cost = 5 
1 + 5 = 6, cost = 6 
Total = 11


任务就是把几个数加起来使得代价最小。

方法1:优先队列 priority_queue。参考 http://blog.csdn.net/frankiller/article/details/7913697

优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。这点类似于给队列里的元素进行了由大互小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。

#include <iostream>  
#include <iomanip>  
#include <string>  
#include <cstring>  
#include <cstdio>  
#include <queue>  
#include <stack>  
#include <algorithm>  
#include <cmath>  
#include <ctime>

using namespace std;

struct cmp
{
	bool operator() (const int &a, const int &b)
	{
		return a > b;
	}
};//重载

priority_queue<int, vector<int>,cmp>q;//定义

int main() 
{
#ifdef Local    
	freopen("a.in", "r", stdin);    
#endif
	int n = 0, i = 0;
	while(cin >> n && n)
	{
		int x = 0, y = 0, cost = 0;
		for (i = 1; i <= n; i++)
		{
			cin >> x;
			q.push(x);
		}
		while(q.size() > 1)
		{
			y = q.top();
			q.pop();
			y += q.top();
			q.pop();
			cost += y;
			q.push(y);
		}
		q.pop();//注意,必须有这个,要保证在下一个test case的时候q为空,不然会影响下一个case的结果。
		cout << cost << endl;
	}
	return 0;
}
STL的都不太懂,太在做题中积累啊!


方法2:“哈尔曼编码的算法。实质就是每次两个最小的相邻数相加,直到只剩一个数为止,然后把过程中所有的和加起来,较难处理的点就是每次加完了要保证下次相加的必须是最小的两个数。
在这里因为看见数据量比较小(5000个),因此用的O(n*n)的办法做的,就是每次做完和都找到相应位置将数字插进去,前面的数依次向前移动一位,以此保证整个序列始终有序;本来想用排序做,但想想如果每加一次qsort排一次序的话,复杂度为(n*n*logn),会更加费时。” ------ http://blog.csdn.net/goomaple/article/details/7823607

和我下面TLE的思想一样,但是我是每次都快排,所以超时间了,可以按照上边说的,求和后找位置插入,比快排要快些。

附上别人的代码

#include<iostream>  
#include<cstdlib>  
#include<cstring>  
#include<cstdio>  
#include<cmath>  
using namespace std;  
const int maxn = 5002;  
int cmp(const void *a, const void *b)  
{  
    return *(int *)a - *(int *)b;  
}  
int main()  
{  
#ifdef test  
    freopen("in.txt", "r", stdin);  
#endif  
    int num;  
    int a[maxn];  
    while(scanf("%d", &num), num)  
    {  
        long long sum = 0;  
        for(int i = 0; i < num; i++)  
            scanf("%d", &a[i]);  
        qsort(a, num, sizeof(a[0]), cmp);  
        for(int i = 0; i < num - 1; i++)  
        {  
            int ans = a[i] + a[i + 1];  
            sum += ans;  
            a[i + 1] = ans;  
            for(int j = i + 1; j < num; j++)  
                if(ans < a[j])   
                {  
                    for(int k = i + 1; k < j - 1; k++) // 找到元素位置将其插入,前面的元素依次向前移一位  
                        a[k] = a[k + 1];  
                    a[j - 1] = ans;  
                    break;  
                }  
                else if(j == num - 1)  
                {  
                    for(int k = i + 1; k < num - 1; k++)  
                        a[k] = a[k + 1];  
                    a[num - 1] = ans;  
                    break;  
                }  
        }  
        printf("%lld\n", sum);  
    }  
    return 0;  
}  


其他:在所有的数中不断选最小相加。结果TLE了!

附TLE代码:

#include <iostream>  
#include <iomanip>  
#include <string>  
#include <cstring>  
#include <cstdio>  
#include <queue>  
#include <stack>  
#include <algorithm>  
#include <cmath>  
#include <ctime>

using namespace std;

const int maxn = 5000+10;
int num[maxn];

int cmp(const void *a, const void *b)
{
	return *(int *)b - *(int *)a;
}

int main() 
{
#ifdef Local    
	freopen("a.in", "r", stdin);    
#endif
	int n = 0;
	while(cin >> n && n)
	{
		memset(num, 0, sizeof(num));
		int i = 0, sum = 0, k = 1, t = 0;
		for(i = 0; i < n; i++)
			cin >> num[i];
		qsort(num, n, sizeof(num[0]), cmp);
		for (i = 0, t = n; i < t-1; i++)
		{
			sum += (num[n-1]+num[n-2]);
			num[n-2] += num[n-1];
			n--;
			qsort(num, n, sizeof(num[0]), cmp);
		}
		cout << sum << endl;
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值