贪心——合并石子

7-8 合并石子 (20分) 合并石子

现在有n堆石子,我们要把它们合并成一堆。 每一次合并,可以把两堆石子(可以不相邻)合并到一起, 消耗的体力等于两堆石子的重量之和。
可以看出,所有的石子经过 n−1 次合并之后,就只剩下一堆了。 在合并石子时总共消耗的体力等于每次合并所耗体力之和。

我们在合并石子时要尽可能地节省体力。假定每个石子重量都为1 , 并且已知石子的堆数和每堆石子的数目,求最少所消耗的体力。

输入格式:

共两行。 第一行是一个整数 n(1≤n≤100000) ,表示石子的堆数。

第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(0≤ai≤100000) 是第 i 堆石子的数目。

输出格式:

一个整数,也就是最小的体力耗费值。

输入样例:

3 1 2 3

输出样例:

9

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<vector>
#include<string>
#define M 100010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int n;
int main(){
    cin >> n;
    priority_queue<int,vector<int>,greater<int> >q;
    int t;
    while(n--){
        scanf("%d",&t);
        q.push(t);
    }
    ll ans = 0;
    while(q.size()>1){
        ll now = 0;
        now += q.top(); q.pop();
        now += q.top(); q.pop();
        q.push(now);
        ans += now;
    }
    cout << ans << endl;
    return 0;
}

自己原本思路:让最轻的移动次数最多
eg
1 2 3
分别需要移动2 2 1次
错误:这个思路是先从最轻的开始,固定住目标堆,其余依次被放入

eg 2 2 3 3
此做法:
(2,2)3 3——(4),3,3————4
(4,3) 3——(7,3)————7
(7,3)——10
总计 21

但是实际上最少:每次动态把最轻的拿出来
(2,2)3,3——3,3,4————4
(3,3)4——4,6————6
(4,6)————10
共计 20

int n;
int a[M];
int main(){
    cin >> n;
    for(int i=0; i<n; i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    ll ans = 0;
    for(int i=0; i<n; i++)
        ans += a[i]*(n-i);
    ans -= a[0];
    cout << ans << endl;
    return 0;
}

合并石子2

现在有n堆石子,我们要把它们合并成一堆。 每一次合并,只能把相邻的两堆石子合并到一起, 消耗的体力等于两堆石子的重量之积。
可以看出,所有的石子经过 n−1 次合并之后,就只剩下一堆了。 在合并石子时总共消耗的体力等于每次合并所耗体力之和。

我们在合并石子时要尽可能地浪费体力。假定每个石子重量都为1 , 并且已知石子的堆数和每堆石子的数目,求最多所消耗的体力。

输入格式:

共两行。 第一行是一个整数 n(1≤n≤100000) ,表示石子的堆数。

第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(0≤ai≤10000) 是第 i 堆石子的数目。

数据保证最终答案在长整型范围以内。

输出格式:

一个整数,也就是最多的体力耗费值。

输入样例:

3 1 2 3

输出样例:

11

合并石子时要尽可能地浪费体力
先合并轻的还是先合并重的:
eg
1 2 3 10
3,3,10——2
6,10——9
16——60——71

1,2,13——30
1,15——26
16——15——71

发现:不管怎么合并都一样:
原因:
eg a b c d-----ab + ac+ ad +bc+ bd +cd
每个石子都乘上了除自己之外的所有石子,所以不管怎么合并,都同

边输入遍运算即可

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<vector>
#include<string>
#define M 100010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int main(){
    ll n,now,pre=0;
    ll ans = 0;
    cin >> n;
    while(n--){
        scanf("%lld",&now);
        ans += now*pre;
        pre += now;
    }
    cout << ans << endl;
    return 0;
}

发布了62 篇原创文章 · 获赞 0 · 访问量 1743

猜你喜欢

转载自blog.csdn.net/jhckii/article/details/104457749