NYOJ 214.單調遞增子序列(二)(動態規劃)
阿新 • • 發佈:2019-01-22
/*
描述
給定一整型數列{a1,a2...,an}(0<n<=100000),找出單調遞增最長子序列,並求出其長度。
如:1 9 10 5 11 2 13的最長單調遞增子序列是1 9 10 11 13,長度為5。
輸入
有多組測試資料(<=7)
每組測試資料的第一行是一個整數n表示序列中共有n個整數,隨後的下一行裡有n個整數,表示數列中的所有元素.每個整形數中間用空格間隔開(0<n<=100000)。
資料以EOF結束 。
輸入資料保證合法(全為int型整數)!
輸出
對於每組測試資料輸出整形數列的最長遞增子序列的長度,每個輸出佔一行。
樣例輸入
7
1 9 10 5 11 2 13
2
2 -1
樣例輸出
5
1
另外,還可以用lower_bound()函式進行查詢(其實上面程式中的二分查詢就相當於該函式)
描述
給定一整型數列{a1,a2...,an}(0<n<=100000),找出單調遞增最長子序列,並求出其長度。
如:1 9 10 5 11 2 13的最長單調遞增子序列是1 9 10 11 13,長度為5。
輸入
有多組測試資料(<=7)
每組測試資料的第一行是一個整數n表示序列中共有n個整數,隨後的下一行裡有n個整數,表示數列中的所有元素.每個整形數中間用空格間隔開(0<n<=100000)。
資料以EOF結束 。
輸入資料保證合法(全為int型整數)!
輸出
對於每組測試資料輸出整形數列的最長遞增子序列的長度,每個輸出佔一行。
樣例輸入
7
1 9 10 5 11 2 13
2
2 -1
樣例輸出
5
1
*/
思路:這道題是求一個數列中,最長的單調子序列。
首先,可以定義兩個陣列a[100010](儲存原數列),dp[100010](儲存最長子序列)。
然後,dp陣列中的元素與a陣列中的某個元素進行比較,如果這個元素比dp陣列最後一個元素大,將這個元素儲存到dp陣列中。(這一部分可以用二分查詢,找到比該元素大於或等於的元素的位置)
最後,輸出dp陣列的個數。
下面是程式碼實現:
#include<stdio.h> #include<string.h> int main() { int n; int a[100005],dp[100005],count; while(~scanf("%d",&n)) { count=0; memset(dp,0x3f,sizeof(dp)); int i; // memset(dp,0,sizeof(dp)); // int i,j; for(i=0;i<n;i++) scanf("%d",&a[i]); for(i=0;i<n;i++)//二分查詢,找到大於或等於該元素的第一個位置 { int low=0,high=count,mid; while(low<=high) { mid=(low+high)/2; if(dp[mid]>=a[i]) high=mid-1; else low=mid+1; } dp[low]=a[i];//將該元素儲存的查詢到的位置 if(low==count)//若該位置是原dp陣列的最後一位,count加1 count++; // for(j=count;j>=0;j--)//從dp陣列的最後一位開始進行比較 // { // (這種方法用於資料量少的,用於資料量大的將有可能超時,需要用到二分查詢) // if(a[i]>dp[j]) //若成立,儲存到dp陣列中 // { // dp[j+1]=a[i]; // if(j==count) // count++; // break; // } // } } printf("%d\n",count); } return 0; }
另外,還可以用lower_bound()函式進行查詢(其實上面程式中的二分查詢就相當於該函式)
下面是程式碼實現:
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; int main() { int n; int a[100005],dp[100005]; while(~scanf("%d",&n)) { fill(dp,dp+n,0x3f3f3f3f); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<n;i++) *(lower_bound(dp,dp+n,a[i]))=a[i]; printf("%d\n",lower_bound(dp,dp+n,0x3f3f3f3f)-dp); } return 0; }