先來說說最長公共子串行,這是一道比較經典的dp題,我們可以很容易寫出
1.狀態f[i][j]表示a序列匹配到第i個b序列匹配到第j個的最長長度
2.狀態轉移方程
f[i][j] = max(f[i-1][j] , f[i][j-1]) (a[i] != b[j])
f[i][j] = f[i-1][j-1]+1(a[i] = b[j])
答案就在f[n][m]中
**
#includeusing namespace std;
int n,m,f[5010][5010];
char a[5010],b[5010];
int main()
}printf("%d",f[n][m]);
return 0;
}
然後我們再來考慮最長公共上公升子串行
1.定義狀態:f[x][y]表示a串匹配長度x,b串匹配長度y,且以b[j]結尾的序列長度。
2.狀態轉移方程:
f[i][j]=f[i][j] = f[i-1][j] (a[i] != b[j])
f[i][j] = max(f[i-1][k]+1) (1 <= k <= j-1 && b[j] > b[k])
對於第乙個方程我們可以理解為當a[i]!=a[j]時我們用b序列去匹配a序列匹配失敗了則a[i]這個數是對這個序列沒有貢獻的,即考慮不考慮都無所謂
對於第二個方程我們可以理解為當b序列中第j個數匹配了,我們可以選擇前面所有的狀態進行轉移,但是保證 b[j] > b[k]
#includeusing namespace std;
int n,m,ans,a[3010],b[3010],f[3010][3010];
int main()
f[i][j]=maxn+1;
} } }
for(int i=1;i<=m;++i) ans=max(ans,f[n][i]);
printf("%d",ans);
return 0;
}
但是這樣的做法在最壞情況下可能到達o(n^3),我們可以考慮優化,我們可以發現在第三重迴圈找最大值時是否可以進行一定優化?我們可以發現當有乙個序列a[i]=b[j]時看第二個轉移方程b[j] > b[k]也就是說a[i]>b[k],我們可以利用乙個最大值maxn來存下每次的最大值,即當a[i]>b[j]時更新它,當a[i]=b[j]時f[i][j]=maxn+1;
#includeusing namespace std;
int n,m,ans,a[3010],b[3010],f[3010][3010];
int main()
} for(int i=1;i<=m;++i) ans=max(ans,f[n][i]);
printf("%d",ans);
return 0;
}
我們依然可以發現f[i][j]轉移只用到了f[i][j-1]的數,我們可以再進行優化!利用滾動陣列優化我們的空間。
#includeusing namespace std;
int n,m,ans,a[3010],b[3010],f[3010];
int main()
} for(int i=1;i<=m;++i) ans=max(ans,f[i]);
printf("%d",ans);
return 0;
}
完結撒花!! 最長公共子串行 最長上公升子串行 最長公共上公升子串行
核心 for int i 1 ifor int j 1 jif a i b j else hdu5248 樹狀陣列優化 nl ogn nlo gn include using namespace std const int maxn 100005 char a maxn int len int bi...
最長上公升子串行 最長公共上公升子串行
求最長公共子串行有幾種方法 include include using namespace std include include const int inf 0x3f3f3f3f const int maxn 10005 int a maxn ints maxn int dp maxn int d...
最長公共上公升子串行
題目描述 給定兩個整數序列,求它們的最長上公升公共子串行。輸入描述 輸入兩組資料,每組資料代表乙個整數序列,其輸入格式為 第一行輸入長度m 1 m 500 第二行輸入該序列的m個整數ai 231 ai 231 輸出描述 輸出共兩行。第一行輸出兩個序列的最長上公升公共子串行的長度l 第二行輸出該子串行...