问题描述:在一个操场的四周摆放着n堆石子,现要将石子有次序地合并成一堆。规定每次至少选2堆至多选k堆石子合并成新的一堆,
合并的费用为新的一堆石子数。计算出将n堆石子合并成一堆的最大总费用和最小总费用。
算法设计:对于给定的n堆石子,计算合并成一堆的最大总费用和最小总费用。
数据输入:文件的第1行有2个正整数n和k,表示有n堆石子,每次至少选2堆至多选k堆石子合并。第2行有n个数,分别表示每堆石子的个数。
输入示例:
7 3
45 13 12 16 9 5 22
输出示例:
593 199
---------------------
#include<iostream>
#include<cstring>
#include<algorithm>
#include<functional>
using namespace std;
int min_k(int *a,int start,int end) //合并k堆
{
int result=0;
for(int i=start;i<end;i++)
{
result+=a[i];
}
return result;
}
int minresult(int *a,int n,int k) //对最小的值贪心,及使得最大的数所加次数最少,及每次按k次合并,并从小到大合并
{
int t=0,min=0,result=0,i,j;
int b[n]; //b数组内数据为新的石子堆中的石子个数
memset(b,0,sizeof(b)); //对b数组清零操作
if(n<k&&n!=1) //当最后石子堆不够k时,直接合并
{
for(int i=0;i<n;i++)
{
result+=a[i];
// cout<<"ai"<<a[i]<<" ";
}
cout<<endl;
return result;
}
if(n==1) //当最后的石子堆刚好为k时,直接返回
{
return result;
}
sort(a,a+n,less<int>()); //升序排序
/*cout<<"数组详情:"<<endl;
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;*/
t=n/k+n%k; //t表示新的数组中的元素个数,即合并后有t个石子堆
for(i=0;i<n/k;i++) //进行n/k次合并,剩余n%k个石子堆留给下次合并
{
b[i]=min_k(a,i*k,i*k+k);
result+=b[i];
//cout<<"b为"<<b[i]<<endl;
}
for(j=i;j<n%k+i;j++) //对余下的石子堆保留,留给下次合并
{
b[j]=a[i*k+j-i];
//cout<<"bj为:"<<b[j]<<endl;
}
return result+=minresult(b,t,k);
}
int maxresult(int *a,int n,int k) //贪心,每次只取最少的,并从大到小合并,这样使得最大的数所加的次数最多,从而得到最大数 ()*(n-1);
{
sort(a,a+n,greater<int>()); //降序排序
int max=(a[0]+a[1])*(n-1);
for(int i=2;i<n;i++)
{
max+=a[i]*(n-i);
}
return max;
}
void solve(int n,int k)
{
int a[n+1];
cout<<"请输入"<<n<<"个石子堆,各堆的石子数:";
for(int i=0;i<n;i++)
{
cin>>a[i];
}
cout<<"最大结果为:"<<maxresult(a,n,k)<<endl;
cout<<"最小结果为:"<<minresult(a,n,k)<<endl;
}
int main()
{
int n,k;
cout<<"请分别输入n和k的值:";
cin>>n>>k;
solve(n,k);
return 0;
}