POJ 3253 Fence Repair 题解 《挑战程序设计竞赛》

题目:POJ - 3253

书中例题。

在看题解之前自己做了一下,用了错误的贪心策略:“越短的木棒切割的时间应该越晚”,局部来看是对的。

正确策略的局部也是这样的。

不过自己的想法不够全面,只想到了第一步。

例如需要1,2,3,4,5 五根木棒,我觉得应该:

先花15的代价切下来长度为5的,

再花10的代价切下来长度为4的,

再花6的代价切下来长度为3的,

最后花3的代价切下来长度为2的,

剩下的也就是长度为1的。

这样代价一共是15+10+6+3=34,而最优策略代价为33.

因此, 虽然说越长的木棒应该最先被切没错,但是对于选择最长木棒这件事,并不是直接从题目所需要的所有长度的木棒里面选最长的,而是:两根次长的也许可以拼成一根比当前最长更长的。

因此应该从小往大遍历,不断选取最短的两根木棒组成新木棒加入所需队列中,换个角度就是说:最短的木棒与次短的木棒应该是兄弟节点。

仔细领会错误和正确策略的区别(懒得开Visio了✧(≖ ◡ ≖✿)):

1+2拼成3,3+3拼成6,此时需要6、5、4三根木棒,6便是最大的,而不是从一开始受限的角度所得出的5。

代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 int n;
 7 int plank[20000];
 8 
 9 void slove() {
10     long long res = 0;
11     
12     while (n > 1) {
13         int min = 0;        //最小的板的下标 
14         int minNext = 1;    //次小的板的下标 
15         
16         if (plank[min] > plank[minNext]) {
17             swap(min, minNext);
18         }
19         
20         for (int i = 2; i < n; i++) {           //找到最小和次小的两块板 
21             if (plank[i] < plank[min]) {
22                 minNext = min;
23                 min = i;
24             }
25             else if (plank[i] < plank[minNext]) {
26                 minNext = i;
27             }
28         }
29         
30         int t = plank[min] + plank[minNext];
31         res += t;
32                 
33         if (min == n - 1) {                //将拼合后的板加入到数组中,去掉原来的 
34             swap(min, minNext); 
35         }
36         plank[min] = t;
37         plank[minNext] = plank[n - 1];
38         
39         n--;         
40     }
41     cout << res << endl;
42 }
43 
44 int main() {
45     cin >> n;
46     for (int i = 0; i < n; i++) {
47         cin >> plank[i];
48     }
49     slove();
50     
51     return 0;    
52 }
原文地址:https://www.cnblogs.com/carolunar/p/6378687.html