nyoj 17 單調遞增最長子序列(dp---記憶化搜尋||窮舉|| nlogn演算法)
阿新 • • 發佈:2018-12-23
單調遞增最長子序列
時間限制:3000 ms | 記憶體限制:65535 KB 難度:4- 描述
- 求一個字串的最長遞增子序列的長度
如:dabdbf最長遞增子序列就是abdf,長度為4- 輸入
- 第一行一個整數0<n<20,表示有n個字串要處理
隨後的n行,每行有一個字串,該字串的長度不會超過10000 - 輸出
- 輸出字串的最長遞增子序列的長度
- 樣例輸入
-
3 aaa ababc abklmncdefg
- 樣例輸出
-
1 3 7
AC程式碼:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=10000+10; int d[maxn]; char s[maxn]; int len; int dp(int i){ int& cur=d[i]; if(cur>0)return cur; cur=1; for(int j=i+1;j<len;j++){ if(s[j]>s[i]){ cur=max(cur,dp(j)+1); } } return cur; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s",s); len=strlen(s); memset(d,0,sizeof(d)); int max1=0; for(int i=0;i<len;i++){ max1=max(max1,dp(i)); } printf("%d\n",max1); } return 0; }
解法二:窮舉 (312ms跑完)
AC程式碼:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=10000+10; char s[maxn]; int dp[maxn]; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s",s); dp[0]=1; int max1=1; int len=strlen(s); for(int i=1;i<len;i++){ dp[i]=1; for(int j=0;j<i;j++){ if(s[i]>s[j]){ if(dp[i]<dp[j]+1){ dp[i]=dp[j]+1; max1=max(max1,dp[i]); } } } } printf("%d\n",max1); } return 0; }
解法3、nlogn演算法 (如果對此演算法不太瞭解,可以網上找相關資料) (4ms跑完)
AC程式碼:
#include<cstdio> #include<cstring> using namespace std; const int maxn=10000+10; char a[maxn]; char B[maxn]; //儲存的是長度為len時的最小末尾 int binary_search(int len,int i){ int first=1,last=len; while(first<last){ int mid=first+(last-first)/2; if(B[mid]>=a[i])last=mid; else first=mid+1; } return first; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s",a); int l=strlen(a); B[1]=a[0]; int len=1; for(int i=1;i<l;i++){ if(a[i]>B[len]){ B[++len]=a[i]; } else { int j=binary_search(len,i); B[j]=a[i]; } } printf("%d\n",len); } return 0; }