動態規划專題(一) HDU1087 最長公共子序列


Super Jumping! Jumping! Jumping!

首先對於動態規划問題要找出其子問題,如果找的子問題是前n個序列的最長上升子序列,但這樣的子問題不好,因為它不具備無后效性,因為它的第n+1的數會影響前n個序列的長度,換句話說,如果第n+1個數加上去不一定使得和前n個數加起來就是最長子序列,具體例子很多比如5,6,1,2 第5個數是3,那么最長序列5,6加3不會比1,2加3長。

比較好的子問題是“求以K個為終點的最長上升子序列”,其實這個子問題的好處在於它限定了一點,終點為第k個數,那么我去遞推第K+1的最長子序列時,它只跟前面各個以某點為終點的最長子序列有關

接下來,我們寫出它的狀態轉移方程

maxLen(k)表示為ak作為終點的最長上升子序列的長度

初始狀態:maxLen(1)=1

maxLen(k)=max{ maxLen(i):1<=i<k且ai < ak 且k>=2}+1

若找不到則maxLen(k)=1

因為以小於ak為終點的各序列,若滿足上述條件,加上ak,一定會形成更長的上升子序列。

另外從認識的角度講,ak是從終點1到k-1一個個判斷下來的那么一旦他們兩個是上升的,連帶的會把ai的最長子序列長度帶上去,使之變得更長。

本題僅作了一個小的改動最長上升總和,思路大致相同,代碼如下

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define MAXN 1005
 5 using namespace std;
 6 int num[MAXN],m[MAXN];//m記錄以每個終點的最長上升總和
 7 int main()
 8 {
 9     int t,i,j,k;
10     while(cin>>t)
11     {
12         if(t==0)
13             break;
14         memset(m,0,sizeof(0));
15         for(i=1;i<=t;i++)
16             scanf("%d",&num[i]);
17         m[1]=num[1];
18         for(i=2;i<=t;i++)
19         {
20             m[i]=num[i];
21             for(j=1;j<i;j++)
22             {
23                 if(num[j]<num[i])
24                     m[i]=max(m[i],m[j]+num[i]);
25             }
26         }
27         k=m[1];
28         for(i=1;i<=t;i++)
29             k=m[i]>k?m[i]:k;
30         cout<<k<<endl;
31     }
32     return 0;
33 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM