题目
分析
每次分割的开销等于自己的长度,其实也等于切割后的小板的长度,那么如果使每次切割的小班的长度组合起来最小,就可以实现每次切割长度最小
于是就把问题转化为——>每次求解最短板与第二短板组合
(类比哈夫曼树)
代码1
普通for循环实现,时间复杂度为n²
#include<iostream>
using namespace std;
typedef long long int ll;
#define N 99999999
int n ,L[N];
void sovle() {
ll ans=0;//计算开销的
while(n>1) { //直到木板的数量为1
//求出最短和第二短板
int min1=0,min2=1;
if(L[min1]>L[min2])//计算数组中第0块和第1块的大小
swap(min1,min2);
for(int i=2; i<n; i++) {
if(L[i]<L[min1]) { //更新最小值
min2=min1;
min1=i;
}
else if(L[i]<L[min2]) {//更新第二小值
min2=i;
}
}
int t=L[min1]+L[min2];//合并
ans+=t;
if(min1==n-1)//如果min1==n-1,则需要交换才能保证其数值t在下一次搜索范围之内
swap(min1,min2);
L[min1]=t;//将合并的值赋值给L[min1]
L[min2]=L[n-1];//将下一轮搜索会忽略掉的数值L[n-1]赋值给第二短
n--;
}
cout<<ans<<endl;
}
int main() {
cin>>n;
for(int i=0; i<n; i++)
cin>>L[i];//每块木板的长度
sovle();
}
代码2
同样的思路,但是采用优先队列实现,算法的时间复杂度为nlongn
#include<iostream>
#include<queue>
#define N 999999
typedef long long ll;
using namespace std;
int n,L[N];
void solve(){
ll ans=0;
//声明一个取值为从小到大的优先数列
priority_queue<int,vector<int>,greater<int>> Q;//priority_queue<int>默认top是最大值
for(int i=0;i<n;i++){
Q.push(L[i]);
}
//循环直到只有一块木板
while(Q.size()>1){//计算队列中的个数
int l1,l2;
l1=Q.top();Q.pop();//取出最小的
l2=Q.top() ;Q.pop() ;//取出第二小的
ans+=l1+l2;//相加
Q.push(l1+l2); //加入队列
}
cout<<ans<<endl;
}
int main(){
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
solve();
}