题意:把木板切成长度如第二行(及以后)的n块(第一行为n)木板,且切断木板耗费的能量为当前木板本身的长度,想办法求出 所需最少能量并输出。
注意:输出结果要用long long 来存,int存不下
思路:先找问题切入点,求出所需最少能量,那就考虑怎样才能在给定的切割方案中寻找最省力的方案。
从这题给的数据来看就要倒过来想问题,也就是说把一段段切好的木板不断合拢回原来长度的过程,每一步都耗费合拢的两块木板长度的力量,怎样才能让每一步耗费的力量最小化即可。
这样问题就清晰了,每一次都找最小的和次小的木板进行合并,直到合并为一个木板,这样每一步都耗费最少的力气,到最后也就是最优的结果,就像哈夫曼编码一个道理。
实现方法:实现方法很简单,用堆来存木板,每次取出两根最短的木板进行合并,再把合并后的木板放回堆中,并记下耗费的力量,直到堆里就剩下一个元素即可(此时木板就合并为一根了)。
java
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import javax.management.Query;
public class Main {
/**
* @param args
*/
static Scanner cin = new Scanner(System.in);
public static void main(String[] args) {
// TODO Auto-generated method stub
while(cin.hasNext()){
solve();
}
}
private static void solve() {
// TODO Auto-generated method stub
int n = cin.nextInt();
Queue< Integer> q = new PriorityQueue<Integer>();
for(int i = 0 ; i < n ; i++){
int t = cin.nextInt();
q.add(t);
}
long ans = 0;
while(q.size() != 1){
int a = q.poll();
int b = q.poll();
ans += a+b;
q.add(a+b);
}
System.out.println(ans);
}
}
C++
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
int n,a[20005],sum;
void solve() //通过模拟解决 O(n^2)
{
int l,r;
long long ans = 0;
while(n > 1)
{
l = 0,r = 1;
if(a[l] > a[r])
swap(l,r);
for(int i = 2 ; i < n ; i++)
if(a[i] < a[l])
{
r = l;
l = i;
}
else if( a[i] < a[r] )
{
r = i;
}
int t = a[l] + a[r];
ans += t;
if(l == n-1)
swap(l,r);
a[l] = t;
a[r] = a[n-1];
n--;
}
printf("%lld\n",ans);
}
void solve_stl() //STL优先级队列解决 n×lg(n)
{
int l,r,t;
long long ans = 0;
priority_queue<int,vector<int>,greater<int> > q;
for(int i = 0 ; i < n ; i++)
q.push(a[i]);
while(q.size() > 1)
{
l = q.top();
q.pop();
r = q.top();
q.pop();
t = l + r;
ans += t;
q.push(t);
}
printf("%lld\n",ans);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
sum = 0;
for(int i = 0 ; i < n ; i++)
{
scanf("%d",&a[i]);
sum += a[i];
}
//solve();
solve_stl();
}
return 0;
}