动态规划:洛谷P1233 木棍加工

洛谷P1233 木棍加工

 

   洛谷的一个普及/提高-的题目,考的是二维的动态规划。

   我的思路:根据本题的描述,这题在状态上有两个维度的转移,长度和宽度,我们不妨将长度从大到小先排序一下,这样只要考虑宽度就可以,问题就转化为了求排序后宽度上的不上升子序列的最小数量,根据dilworth定理,题目就转化为了求最长上升子序列的长度。我们可以用二分法来动规,时间复杂度为nlogn,二分动规的具体原理可以看我的 洛谷 P1020 [NOIP1999 普及组] 导弹拦截 的原理方法。 排序时也要注意,当长度相同时,应该return a.宽度大于b.宽度,否则答案会错。

  我的代码:

 1 //P1233 木棍加工
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 struct stick
 7 {
 8     int l,w;
 9 }s[5001];
10 bool cmp(stick a, stick b)
11 {
12     if (a.l == b.l)
13         return a.w > b.w;//当长度相同时 要按照宽度排序
14     return a.l > b.l;
15 }
16 int dp[5001];
17 int main()
18 {
19     int n;
20     cin >> n;
21     for (int i = 0; i < n; ++i)cin >> s[i].l >> s[i].w;
22     sort(s, s + n, cmp);//先把长度排序好 再求宽度 
23     //就把二维转化为了一维的dp 求这个序列最少能分割为多少个不上升的子序列
24     //根据dilworth定理 一个序列中不上升的子序列数量等于最大上升子列的长度
25     //利用二分 来动规 时间复杂度nlogn
26     int len = 0;
27     dp[len] = s[0].w;//要先给dp[0]初始化为s的第一个元素
28     for (int i = 1; i < n; ++i)
29     {
30         if (s[i].w > dp[len])
31             dp[++len] = s[i].w;
32         else
33         {
34             int p = lower_bound(dp, dp + len, s[i].w)-dp;//用指针得到下标 因为lowerbound返回的是地址指针
35             dp[p] = s[i].w;
36 
37         }
38     }
39     cout << len+1;//这个地方要加1 因为我们的dp数组是从0开始的
40     return 0;
41     
42 }

 

通过!:

 

posted @ 2022-04-11 22:52  朱朱成  阅读(102)  评论(0编辑  收藏  举报