做加法要付出的代价(cost) 定义为这2个数的总和,所以要加1 和10 所需付出的代价为11 。假如你想要加1, 2 和3,那么有以下几种方法:
1 + 2 = 3, cost = 3 | 1 + 3 = 4, cost = 4 | 2 + 3 = 5, cost = 5 |
方法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;
}
}