zoukankan      html  css  js  c++  java
  • hdu 1950 最长上升子序列(lis) nlogn算法【dp】

    这个博客说的已经很好了。http://blog.csdn.net/shuangde800/article/details/7474903

    简单记录一下自己学的:

    问题就是求一个数列最长上升子序列的长度。

    如果子序列长度相同,那么末尾小的子序列更有可能成为最长的子序列。所以就用一个l数组存当子序列长度为len时最小的末尾元素。如果序列下一个值比l[len]大,说明上升子序列长度增加,那么l[len++]=a[i];如果是小,就想办法把它插入到了l数组中....

    HDU 1950 说白了就是求lis:

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=40005;
     5 int a[maxn],l[maxn];
     6 int len,n;
     7 
     8 int lis()
     9 {
    10     len=1;
    11     l[0]=a[0];
    12     for (int i=1;i<n;i++){
    13         if(a[i]>l[len-1])
    14             l[len++]=a[i];
    15         else
    16             *lower_bound(l,l+len,a[i])=a[i];
    17     }
    18     return len;
    19 }
    20 
    21 int main()
    22 {
    23     int T;
    24     cin>>T;
    25     while(T--)
    26     {
    27         cin>>n;
    28         for (int i=0;i<n;i++)
    29             cin>>a[i];
    30         cout<<lis()<<endl;
    31     }
    32     return 0;
    33 }

     这个是二分写法(感觉二分用的最广):

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=40005;
     5 int a[maxn],l[maxn];
     6 int len,n;
     7 
     8 int bin_search(int key)
     9 {
    10     int left, right, mid;
    11     left = 1, right = len;//应该是数据比较水,这样写是左闭右开区间查找,严格来说应该是right=len+1
    12     while (left<right)
    13     {
    14         mid = (left + right) >> 1;
    15         if (l[mid] >= key)
    16             right = mid;
    17         else left = mid + 1;
    18     }
    19     return left;
    20 }
    21 
    22 int lis()
    23 {
    24     len = 1;
    25     l[1] = a[1];
    26     for (int i = 2; i <= n; i++) {
    27         if (a[i] > l[len])
    28             l[++len] = a[i];
    29         else {
    30             int pos = bin_search(a[i]);
    31             l[pos] = a[i];
    32         }
    33     }
    34     return len;
    35 }
    36 
    37 int main()
    38 {
    39     int T;
    40     cin >> T;
    41     while (T--)
    42     {
    43         cin >> n;
    44         for (int i = 1; i <= n; i++)
    45             cin >> a[i];
    46         cout << lis() << endl;
    47     }
    48     return 0;
    49 }

     二分也可以这样写 (查找第一个大于或等于key的元素):

     1 int bin_search(int key)
     2 {
     3     while(left<=right)
     4     {
     5         mid=(left+right)>>1;
     6         if(l[mid]>=key)
     7             right=mid-1;
     8         else left=mid+1;
     9     }
    10     return left;
    11 }

    还有一种是用stl里的set写,原理和上面一样,感觉用的好精妙:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<set>
     4 using namespace std;
     5 const int MAXN = 40005;
     6 set<int> st;
     7 set<int>::iterator it;
     8 int a[MAXN];
     9 
    10 int main()
    11 {
    12     int T, n;
    13     cin >> T;
    14     while (T--)
    15     {
    16         st.clear();
    17         cin >> n;
    18         for (int i = 1; i <= n; i++) {
    19             cin >> a[i];
    20             if (st.count(a[i])) continue;
    21             st.insert(a[i]);
    22             it = st.find(a[i]);
    23             it++;
    24             if (it != st.end())
    25                 st.erase(it);
    26         }
    27         cout << st.size() << endl;
    28     }
    29     return 0;
    30 }

    当然,还有更精妙的:

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int INF = 0x3f3f3f3f;
     5 const int N = 50000;
     6 int a[N],dp[N];
     7 
     8 int main()
     9 {
    10     int T, n;
    11     cin >> T;
    12     while (T--)
    13     {
    14         cin >> n;
    15         for (int i = 0; i < n; i++) {
    16             cin >> a[i]; dp[i] = INF;
    17         }
    18         for (int i = 0; i < n; i++)
    19             *lower_bound(dp, dp + n, a[i]) = a[i];
    20         cout << lower_bound(dp, dp + n, INF) - dp << endl;
    21     }
    22     return 0;
    23 }
  • 相关阅读:
    Linux 通过sendmail 发邮件到外部邮箱
    基于Ruby的Watir-WebDriver自动化测试方案
    高性能Linux服务器构建实战笔记
    Unix Linux 通用vi命令,使用帮助手册【珍藏版】
    软件测试人员必备Linux命令(初、中、高级)
    网络七层知多少,学以致用
    手机终端高级测试工程师经验总结
    临别前夕,工作总结 于2014年8月13日 终稿
    基于ruby的watir自动化测试 笔记二
    高级软件测试工程师笔试题
  • 原文地址:https://www.cnblogs.com/zxhyxiao/p/7259833.html
Copyright © 2011-2022 走看看