HDU 1025 高效最长上升子序列(二分查)

来源:互联网 发布:文化冷战与网络权利 编辑:程序博客网 时间:2024/05/16 15:01

用到了LIS(Longest Increasing Subsequence)最长上升(不下降)子序列,它有两种算法复杂度为O(n*logn)和O(n^2)。前者使用二分查找,后者朴素查找。它的算法大致思路:设置两个a,b数组,a数组存储数据,b数组存储最长不降序序列。此算法关键在于设计二分查找。

刚开始用到了朴素dp算法,果断超时,超时代码为:

 #include <iostream>#include <algorithm>using namespace std;const int Max = 500010;int dp[Max];typedef struct {    int x, y;} Node;Node node[Max];int cmp(const void * a, const void * b){    return (*(Node*)a).x - (*(Node*)b).x;}int main(){    int n;    int t = 1;    while(cin >> n)    {        memset(dp, 0, sizeof(dp));        for(int i = 0; i < n; i++)            scanf("%d%d", &node[i].x, &node[i].y);        //qsort(node, n, sizeof(Node), cmp);        /*for(int i = 0;  i < n; i++)            printf("%d %d\n", node[i].x, node[i].y);*/        for(int i = 0; i < n; i++)        {            dp[i] = 1;            for(int j = i - 1; j >= 0; j--)            {                if(dp[j] + 1 > dp[i] && node[i].y > node[j].y)                    dp[i] = dp[j] + 1;            }        }        int max = 0;        for(int i = 0; i < n; i++)            if(dp[i] > max)                max = dp[i];        printf("Case %d:\n", t++);        printf("My king, at most %d road can be built.\n\n", max);    }    return 0;}


改进后,用到二分查找,一直莫名奇妙Wa,还没找到原因,数据上有问题?

Wa代码:

#include <iostream>#include <algorithm>using namespace std;const int Max = 500010;int dp[Max];int B[Max];typedef struct {int x, y;} Node;Node node[Max];int cmp(const void * a, const void * b){return (*(Node*)a).x - (*(Node*)b).x;}int main(){freopen("1025.txt", "r", stdin);int n;int t = 1;while(cin >> n){memset(dp, 0, sizeof(dp));memset(B, 0, sizeof(B));for(int i = 0; i < n; i++)scanf("%d%d", &node[i].x, &node[i].y);qsort(node, n, sizeof(Node), cmp);B[0] = -1000;B[1] = node[0].y;int len = 1;int p, r, m;for(int i = 1; i < n; i++){p = 1; r = len;while(p <= r){m = (p+r) / 2;if(B[m] < node[i].y) p = m + 1;elser = m - 1;}B[p] = node[i].y;if(p > len) len = p;}printf("Case %d:\n", t++);printf("My king, at most %d road can be built.\n\n", len);}return 0;}

最后是AC代码,源于http://www.cnblogs.com/hankers/archive/2012/02/07/2340904.html

#include<stdio.h> int dp[50005],a[50005];  int Lis(int n) {     int len=1,i,low,high,mid;     dp[1]=a[1];     for(i=2;i<=n;i++)     {        low=1;        high=len;        while(low<=high)        {            mid=(low+high)/2;            if(a[i]>dp[mid])                low=mid+1;            else                high=mid-1;        }        dp[low]=a[i];        if(low>len)            len=low;     }     return len; } int main() {     int n,x,y,i,ans,k=1;     while(scanf("%d",&n)!=EOF)     {         for(i=0;i<n;i++)         {             scanf("%d%d",&x,&y);             a[x]=y;         }         ans=Lis(n);         printf("Case %d:\n",k++);         if(ans==1)             printf("My king, at most 1 road can be built.\n");         else             printf("My king, at most %d roads can be built.\n",ans);         printf("\n");     }     return 0; }

其实显然这个数组开小了,不过能ac。

改天继续查找Wa原因

原创粉丝点击