1. 程式人生 > >nyoj 17 單調遞增最長子序列(dp---記憶化搜尋||窮舉|| nlogn演算法)

nyoj 17 單調遞增最長子序列(dp---記憶化搜尋||窮舉|| nlogn演算法)

單調遞增最長子序列

時間限制:3000 ms  |  記憶體限制:65535 KB 難度:4
描述
求一個字串的最長遞增子序列的長度
如:dabdbf最長遞增子序列就是abdf,長度為4
輸入
第一行一個整數0<n<20,表示有n個字串要處理
隨後的n行,每行有一個字串,該字串的長度不會超過10000
輸出
輸出字串的最長遞增子序列的長度
樣例輸入
3
aaa
ababc
abklmncdefg
樣例輸出
1
3
7
分析:動態規劃思想,記憶化搜尋  (508ms跑完)

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;
}