【动态规划+二分查找】POJ2533&POJ1631最长上升子序列(LIS)

POJ2533裸的LIS,时间复杂度为O(n^2)

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int MAXN=1000+5;
 5 int a[MAXN];
 6 int dp[MAXN];
 7 int n,ans;
 8 
 9 int main()
10 {
11     scanf("%d",&n);
12     for (int i=0;i<n;i++)
13     {
14         scanf("%d",&a[i]);
15         dp[i]=1;
16     }
17     ans=-1;
18     for (int i=1;i<n;i++)
19     {
20         for (int j=0;j<i;j++)
21             if (a[j]<a[i] && dp[j]+1>dp[i]) 
22             {
23                 dp[i]=dp[j]+1;
24             }
25         if (dp[i]>ans) 
26             {
27                 ans=dp[i];
28             }
29     }
30     cout<<ans<<endl;
31     return 0;
32 }

POJ1631

两条线路i与j不交叉的前提条件是a[i]<a[j],即上升子序列。用二分搜索+LIS,时间复杂度为O(n^2),具体解释详见《挑战程序设计竞赛2.3记录结果在利用的“动态规划”》P65

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int MAXN=40000+5;
 5 const int INF=1000000+5;
 6 int a[MAXN];
 7 int dp[MAXN];//dp[i]表示长度为i+1的上升子序列末位元素的最小值 
 8 int n,m,ans,l,r;
 9 
10 int search(int k)
11 {
12     int ul=l,ur=r;
13     while (ur-ul>1)
14     {
15         int mid=(ur+ul)/2;
16         if (dp[mid]>=k) ur=mid;
17             else ul=mid;
18     }
19     return ur;
20 }
21 
22 int main()
23 {
24     scanf("%d",&m);
25     for (int kase=0;kase<m;kase++)
26     {
27         scanf("%d",&n);
28         for (int i=0;i<n;i++)
29         {
30             scanf("%d",&a[i]);
31             dp[i]=INF;
32         }
33         l=-1;
34         r=0;
35         for (int i=0;i<n;i++)
36         {
37             int pos=search(a[i]);
38             dp[pos]=a[i];
39             if (pos==r) r++;
40         }
41         cout<<r<<endl;
42     }
43     return 0; 
44 }
原文地址:https://www.cnblogs.com/iiyiyi/p/4638188.html