1. 程式人生 > >動態規劃入門 COGS1398 最長上升子序列

動態規劃入門 COGS1398 最長上升子序列

1398. 最長上升子序列

★   輸入檔案:lis1.in   輸出檔案:lis1.out   簡單對比
時間限制:1 s   記憶體限制:256 MB

【題目描述】

設有整數序列A[1],A[2],A[3],…,A[m],若存在下標i1<i2<i3<…<in,且A[i1]<A[i2]<A[i3]<…<A[in],則稱 序列A[1],A[2],A[3],…,A[m]中有長度為n的上升子序列A[i1] , A[i2] ,A[i3] ,…,A[in]。

請程式設計計算指定序列的最長上升子序列長度。

【輸入格式】

第一行一個正整數n(n<1001),表示序列中整數個數;

第二行是空格隔開的n個整陣列成的序列。

【輸出格式】

一個正整數,表示輸入檔案中整數序列的最長上升子序列的長度。

【樣例輸入】

  7

1 7 3 5 9 4 8

【樣例輸出】

4

【樣例說明】

j

i

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int n;
 8 int in[10010],f[10010];
 9 int ans;
10 
11 int main(){
12     scanf("%d
",&n); 13 for(int i=1;i<=n;i++) scanf("%d",&in[i]),f[i]=1; 14 for(int i=2;i<=n;i++){ 15 for(int j=1;j<i;j++) 16 if(in[i]>in[j]) f[i]=max(f[i],f[j]+1); 17 ans=max(ans,f[i]); 18 } 19 printf("%d",ans); 20 return 0; 21 }

單調棧優化

從前向後掃描序列列,維護一個單調棧

插⼊入一個數時,我們在h[] 中二分出一個位置i,使得h[i]<a[k+1]<=h[i + 1],令h[i+1]=a[k + 1] 即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int n;
 8 int num[10010];
 9 int top;
10 int tmp;
11 
12 void add(int t){
13     if(t>num[top]) num[++top]=t;
14     else{
15         int ll=1;
16         int rr=top;
17         int mid;
18         while(ll<=rr){
19             mid=(ll+rr)>>1;
20             if(t>num[mid]) ll=mid+1;
21             else rr=mid-1;//注意-1和+1
22         }
23         num[ll]=t;
24     }
25     return;
26 }
27 
28 int main(){
29     scanf("%d",&n);
30     num[0]=-1;
31     for(int i=1;i<=n;i++) scanf("%d",&tmp),add(tmp);
32     printf("%d",top);
33     return 0;
34 } 

樹狀陣列優化

陣列離散化並用樹狀陣列維護字首最大值

 1 //實為最長上升子序列 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 int n;
 9 int in[10010],val[10010];
10 int len;
11 int b[10010];//b[i]以數字i結尾的子序列最長可以為的值 
12 //掃描到in[k]這個位置時,b[i]中只有b[a[k]]會改變
13 //b[a[k]]=max(b[i]+1|i<a[k])  
14 int ans,temp;
15 
16 void add(int v,int pos){
17     for(int i=pos;i<=len;i+=i&(-i)) b[i]=max(v,b[i]);
18     return; 
19 }
20 
21 int ask(int pos){
22     int t=0;
23     for(int i=pos;i;i-=i&(-i)) t=max(t,b[i]);
24     return t;
25 } 
26 
27 int main(){
28     scanf("%d",&n);
29     for(int i=1;i<=n;i++) scanf("%d",&in[i]),val[i]=in[i];
30     sort(val+1,val+n+1);
31     len=unique(val+1,val+n+1)-val;//去重 保證最長上升
32     memset(b,0,sizeof(b));
33     ans=1;
34     for(int i=1;i<=n;i++){
35         in[i]=lower_bound(val+1,val+len+1,in[i])-val+1;//離散化???高大上 
36         temp=ask(in[i]-1)+1;
37         ans=max(ans,temp);
38         add(temp,in[i]);
39     }
40     printf("%d",ans);
41 }

線段樹優化

可以用樹狀陣列優化,那麼顯然可用線段樹

然而我碼了2K掛掉了,以後再補