ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目:http://poj.org/problem?id=3253
题意:
把一块木板切成指定的n段,一共切n-1段,每切一段的花费是木板的长度,安培切木板的顺序使得花费最少,输出最小值
题解:
类似于合并石头,这里是分木板,把一个木板长度L,分为L1,L2的花费为L
问分为指定的n断花费最小为多少。
21
13 8 分为 13 和 8 花费21
8 5 分为 8 和 5 花费13
画出这样的树,我们可以发现每次要先把最小的两个切出来,但是要切最小和次小的两个就必须要把父节点切出来,依次往上切。。。
所以问可以把切割问题转换为合并问题,把最小和次小的两个合并,成为新的子节点,计算花费,再依次往上合并直到只有一个节点
可以类别一下合并石头和poj 2054树的染色(先染父节点才能染字节点,但是我们是选择字节开始染色的,然后才去染父节点)
简而言之,就是,刀刀最小(从后往前,当前切这一刀的状态假定前面的切好了,直到一个确定的状态,就是木板一分为二的状态)
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n;
ll ans=0;
priority_queue<int, vector<int>, greater<int> > q;
void solve(){
int cost;
while(q.size()>=2){
cost = q.top();q.pop();
cost += q.top();q.pop();
ans+=cost;
q.push(cost);
}
cout<<ans<<endl;
}
int main(){
scanf("%d",&n);
int x;
fo(i,1,n){
scanf("%d",&x);
q.push(x);
}
solve();
return 0;
}