木棍加工——线性dp、dilworth定理、最长上升子序列

P1233 木棍加工 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

读题可知我们要求的是将所有木棍分割成长度与宽度都是不上升子序列的序列个数。

既然是不上升子序列,那么我们就结构体排序一下。

1 bool cmp(const node&s1,const node&s2)
2 {
3     if(s1.l==s2.l)return s1.w>s2.w;
4     return s1.l>s2.l;
5 }

 

根据dilworth定理:

  一个序列要最少分割为多少个不上升子序列的个数等于该序列最长上升子序列的长度。

  注意:虽然问题转化为求最长上升子序列,但是该序列仍应该是排好序的原本序列,而不是再将序列排成从小到大上升的序列进行求值。是在原序列基础上求的长度!!

 

那么问题就转化为求该序列的最长上升子序列的长度。

方法1:O(n^2)

  状态表示:排序后以第i个数字为终点的最长上升子序列的长度

  状态计算:j从1到i-1遍历一遍,如果符合上升的要求(j的宽度小于i的宽度)那就f[i]=max(f[j]+1,f[i])。

       如果不符合上升的要求,那就continue

  问题:为什么符合上升的要求只需要考虑宽度,不考虑长度呢?

  回答:因为咱们总序列的排序就是按照长度由大到小排的,相当于把长度这一维给看作定值,通过求宽度由小到大的最长上升子序列长度来得到答案(这是由dilworth定理推出来的)。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=5e3+100;
 4 struct node
 5 {
 6     int l,w;
 7 }e[N];
 8 int f[N];
 9 bool cmp(const node&s1,const node&s2)
10 {
11     if(s1.l==s2.l)return s1.w>s2.w;
12     return s1.l>s2.l;
13 }
14 int main()
15 {
16     int n;scanf("%d",&n);
17     for(int i=1;i<=n;i++)scanf("%d%d",&e[i].l,&e[i].w);
18     sort(e+1,e+1+n,cmp);
19     
20     int ans=0;
21     for(int i=1;i<=n;i++)
22     {
23         f[i]=1;
24         for(int j=1;j<i;j++)
25         {
26             if(e[j].w<e[i].w&&f[i]<f[j]+1)
27                 f[i]=f[j]+1;
28         }
29         ans=max(ans,f[i]);
30     }
31     
32     printf("%d\n",ans);
33     
34     
35     return 0;
36 }
View Code

 

方法2:O(nlogn)

  状态表示:排序后以第i个数字为终点的上升子序列结尾的最小值。

  状态计算:用i将序列遍历一遍,如果第i个结构体的宽度大于f[ans],那么f[++ans]=第i个结构体的宽度。

       否则,就二分求大于等于第i个结构体宽度的最小的那个位置k,f[k]=第i个结构体的宽度。

       最后答案求的是最长上升子序列的长度,也就是ans的大小啦。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=5e3+100;
 4 int f[N],ans;
 5 struct node
 6 {
 7     int l,w;
 8 }e[N];
 9 
10 bool cmp(const node&s1,const node&s2)
11 {
12     if(s1.l==s2.l)return s1.w>s2.w;
13     return s1.l>s2.l;
14 }
15 
16 int main()
17 {
18     int n;scanf("%d",&n);
19     for(int i=1;i<=n;i++)scanf("%d%d",&e[i].l,&e[i].w);
20     
21     sort(e+1,e+1+n,cmp);
22     for(int i=1;i<=n;i++)
23     {
24         if(e[i].w>f[ans])f[++ans]=e[i].w;
25         else
26         {
27             int k=lower_bound(f+1,f+1+ans,e[i].w)-f;
28             f[k]=e[i].w;
29         }
30     }
31     
32     printf("%d\n",ans);
33     
34     return 0;
35 } 
View Code

 

posted @ 2022-04-04 16:09  wellerency  阅读(151)  评论(0编辑  收藏  举报