日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

最長公共上升子序列

系統 2341 0

簡稱LCIS,在串a和b中,有串c為串a和b的公共串,且c(i-1)<=c(i)<=c(i+1)并且c為所有公共上升子序列中最長串。

/*轉自 http://wenku.baidu.com/view/3e78f223aaea998fcc220ea0.html

定義狀態F[i][j]表示以a串的前i個字符b串的前j個字符且以b[j]為結尾構成的LCIS的長度。

為什么是這個而不是其他的狀態定義?最重要的原因是我只會這個,還有一個原因是我知道這個定義能搞到平方的算法。而我這只會這個的原因是,這個狀態定義實在是太好用了。這一點我后面再說。

我們來考察一下這個這個狀態。思考這個狀態能轉移到哪些狀態似乎有些棘手,如果把思路逆轉一下,考察這個狀態的最優值依賴于哪些狀態,就容易許多了。這個狀態依賴于哪些狀態呢?

首先,在a[i]!=b[j]的時候有F[i][j]=F[i-1][j]。為什么呢?因為F[i][j]是以b[j]為結尾的LCIS,如果F[i][j]>0那么就說明a[1]..a[i]中必然有一個字符a[k]等于b[j](如果F[i][j]等于0呢?那賦值與否都沒有什么影響了)。因為a[k]!=a[i],那么a[i]對F[i][j]沒有貢獻,于是我們不考慮它照樣能得出F[i][j]的最優值。所以在a[i]!=b[j]的情況下必然有F[i][j]=F[i-1][j]。這一點參考LCS的處理方法。

那如果a[i]==b[j]呢?首先,這個等于起碼保證了長度為1的LCIS。然后我們還需要去找一個最長的且能讓b[j]接在其末尾的LCIS。之前最長的LCIS在哪呢?首先我們要去找的F數組的第一維必然是i-1。因為i已經拿去和b[j]配對去了,不能用了。并且也不能是i-2,因為i-1必然比i-2更優。第二維呢?那就需要枚舉b[1]..b[j-1]了,因為你不知道這里面哪個最長且哪個小于b[j]。這里還有一個問題,可不可能不配對呢?也就是在a[i]==b[j]的情況下,需不需要考慮F[i][j]=F[i-1][j]的決策呢?答案是不需要。因為如果b[j]不和a[i]配對,那就是和之前的a[1]..a[j-1]配對(假設F[i-1][j]>0,等于0不考慮),這樣必然沒有和a[i]配對優越。(為什么必然呢?因為b[j]和a[i]配對之后的轉移是max(F[i-1][k])+1,而和之前的i`配對則是max(F[i`-1][k])+1。顯然有F[i][j]>F[i`][j],i`>i)

于是我們得出了狀態轉移方程:

a[i]!=b[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]?

不難看到,這是一個時間復雜度為O(n^3)的DP,離平方還有一段距離。

但是,這個算法最關鍵的是,如果按照一個合理的遞推順序,max(F[i-1][k])的值我們可以在之前訪問F[i][k]的時候通過維護更新一個max變量得到。怎么得到呢?首先遞推的順序必須是狀態的第一維在外層循環,第二維在內層循環。也就是算好了F[1][len(b)]再去算F[2][1]。 如果按照這個遞推順序我們可以在每次外層循環的開始加上令一個max變量為0,然后開始內層循環。當a[i]>b[j]的時候令max=F[i-1][j]。如果循環到了a[i]==b[j]的時候,則令F[i][j]=max+1。

最后答案是F[len(a)][1]..F[len(a)][len(b)]的最大值。*/

PS: a[i] > b[j]的原因: 因為由上面的轉移有到b[j] > b[k],當a[i] == b[j]時,我們得到a[i] > b[k],而這個k就是在a[i] != b[j]的時候找的,也就是說 a[i] > b[j]時得到的F[i-1][j]屬于F[i-1][k]。

其實可以優化為1維的,因為F[i][j]中i是嚴格上升,可以用滾動數組。

在此基礎上壓掉了一維空間(時間還是平方)。i循環到x的時候,F[i]表示原來F[x][j]。之所以可以這樣,是因為如果a[i]!=b[j],因為F[x][j]=F[x-1][j]值不變,F[x]不用改變,沿用過去的就好了,和這個比較維護更新得到的max值依然是我們要的。而a[i]==b[j]的時候,就改變F[x]的值好了。具體結合代碼理解。

可以得到:

a[i]>b[j]: ? Max=max{Max, F[j]}?

a[i]==b[j]: ? F[j]=Max+1

參考代碼:

    #include <iostream>

using namespace std;

#define ll long long

const int MAXN = 3005;

int max(const int& a, const int& b){return a>b?a:b;}

ll f[MAXN], a[MAXN], b[MAXN];

int n;

int main()

{

	cin >> n;

	int i, j, k;

	for(i = 1; i <= n; i++) cin >> a[i];

	for(i = 1; i <= n; i++) cin >> b[i];

	ll ans = 0, maxi = 0;;

	for(i = 1; i <= n; i++)

	{

		maxi = 0;

		for(j = 1; j <= n; j++)

			if(a[i] > b[j] && maxi < f[j]) maxi = f[j];

			else if(a[i] == b[j]) f[j] = maxi+1, ans = max(ans, f[j]); //我們在這里直接維護ans就ok

	}

	cout << ans;	

	return 0;

}
  

參考例題: http://wikioi.com/problem/1408/

最長公共上升子序列


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 咸宁市| 西安市| 长岛县| 富宁县| 旺苍县| 北宁市| 会昌县| 兴山县| 康乐县| 定边县| 秀山| 健康| 宜兰市| 焉耆| 鄯善县| 荔波县| 祥云县| 夏邑县| 乌拉特中旗| 深圳市| 和龙市| 尼勒克县| 财经| 醴陵市| 曲靖市| 巴里| 昭通市| 绥芬河市| 青川县| 仪陇县| 乌苏市| 清涧县| 泰和县| 锡林浩特市| 江陵县| 句容市| 绥滨县| 武功县| 阳朔县| 乾安县| 新沂市|