首页 > 技术文章 > 51nod 1117 聪明的木匠 (贪心)

nowandforever 2015-04-13 12:17 原文

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1117

跟挑战程序书上例题一样,将要切割的n断木板,分别对应二叉树树的叶子节点,则切割的总开销为木板的长度×节点的深度,可以画图理解,那么最短的木板(L1)应当是深度最大的叶子节点之一,次短的板(L2)和它是兄弟节点,由一块长度是(L1+L2) 的木板切割而来,这样可以变成(n-1)块木板,然后递归求解到n==1。

书上贪心部分用的是O(n×n) 的算法  在这里会超时,需要2.4节优先队列O(NlogN)的算法。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <vector>
 5 #include <cstring>
 6 #include <string>
 7 #include <algorithm>
 8 #include <string>
 9 #include <set>
10 #include <functional>
11 #include <numeric>
12 #include <sstream>
13 #include <stack>
14 #include <map>
15 #include <queue>
16 
17 #define CL(arr, val)    memset(arr, val, sizeof(arr))
18 
19 #define ll long long
20 #define inf 0x7f7f7f7f
21 #define lc l,m,rt<<1
22 #define rc m + 1,r,rt<<1|1
23 #define pi acos(-1.0)
24 
25 #define L(x)    (x) << 1
26 #define R(x)    (x) << 1 | 1
27 #define MID(l, r)   (l + r) >> 1
28 #define Min(x, y)   (x) < (y) ? (x) : (y)
29 #define Max(x, y)   (x) < (y) ? (y) : (x)
30 #define E(x)        (1 << (x))
31 #define iabs(x)     (x) < 0 ? -(x) : (x)
32 #define OUT(x)  printf("%I64d\n", x)
33 #define lowbit(x)   (x)&(-x)
34 #define Read()  freopen("a.txt", "r", stdin)
35 #define Write() freopen("b.txt", "w", stdout);
36 #define maxn 1000000000
37 #define N 50005
38 using namespace std;
39 
40 int L[N];
41 int main()
42 {
43    // Read();
44     int n;
45     long long ans=0;
46     scanf("%d",&n);
47     for(int i=0;i<n;i++) scanf("%d",&L[i]);
48     while(n>1)
49     {
50         int m1=0,m2=1;
51         if(L[m1]>L[m2]) swap(m1,m2);
52         for(int i=2;i<n;i++)
53         {
54             if(L[m1]>L[i])
55             {
56                 m2=m1;
57                 m1=i;
58             }
59             else if(L[m2]>L[i])
60             {
61                 m2=i;
62             }
63         }
64         //printf("%d %d\n",L[m1],L[m2]);
65         int t=L[m1]+L[m2];
66         ans+=t;
67         if(m1==n-1) swap(m1,m2);
68         L[m1]=t;
69         L[m2]=L[n-1];
70         n--;
71     }
72     printf("%lld\n",ans);
73     return 0;
74 }

优化后的代码:每次只需要选择长度最小的两块木板,则用优先队列从小到大排序,每次把取出来的两块木板之和压进队列即可。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <vector>
 5 #include <cstring>
 6 #include <string>
 7 #include <algorithm>
 8 #include <string>
 9 #include <set>
10 #include <functional>
11 #include <numeric>
12 #include <sstream>
13 #include <stack>
14 //#include <map>
15 #include <queue>
16 
17 #define CL(arr, val)    memset(arr, val, sizeof(arr))
18 
19 #define ll long long
20 #define inf 0x7f7f7f7f
21 #define lc l,m,rt<<1
22 #define rc m + 1,r,rt<<1|1
23 #define pi acos(-1.0)
24 
25 #define L(x)    (x) << 1
26 #define R(x)    (x) << 1 | 1
27 #define MID(l, r)   (l + r) >> 1
28 #define Min(x, y)   (x) < (y) ? (x) : (y)
29 #define Max(x, y)   (x) < (y) ? (y) : (x)
30 #define E(x)        (1 << (x))
31 #define iabs(x)     (x) < 0 ? -(x) : (x)
32 #define OUT(x)  printf("%I64d\n", x)
33 #define lowbit(x)   (x)&(-x)
34 #define Read()  freopen("a.txt", "r", stdin)
35 #define Write() freopen("b.txt", "w", stdout);
36 #define maxn 1000000000
37 #define N 50005
38 using namespace std;
39 
40 int L[N];
41 priority_queue<int, vector<int>, greater<int> >que;
42 int main()
43 {
44     //Read();
45     int n;
46     scanf("%d",&n);
47     for(int i=0;i<n;i++)
48     {
49         scanf("%d",&L[i]);
50         que.push(L[i]);
51     }
52     ll ans=0;
53     while(que.size()>1)
54     {
55         int l1,l2;
56         l1=que.top();
57         que.pop();
58         l2=que.top();
59         que.pop();
60         ans+=l1+l2;
61         que.push(l1+l2);
62     }
63     printf("%lld\n",ans);
64     return 0;
65 }

推荐阅读