1120 病毒 csuOJ 最長公共公升子串行

2021-06-25 10:57:58 字數 2771 閱讀 9896

time limit: 3 sec  memory limit: 128 mb

submit: 259  solved: 96

[submit][status][web board]

你有乙個日誌檔案,裡面記錄著各種系統事件的詳細資訊。自然的,事件的時間戳按照嚴格遞增順序排列(不會有兩個事件在完全相同的時刻發生)。

遺憾的是,你的系統被病毒感染了,日誌檔案中混入了病毒生成的隨機偽事件(但真實事件的相對順序保持不變)。備份的日誌檔案也被感染了,但由於病毒採用的隨機感染方法,主日誌檔案和備份日誌檔案在感染後可能會變得不一樣。

給出被感染的主日誌和備份日誌,求真實事件序列的最長可能長度。

輸入第一行為資料組數t (t<=100)。每組資料報含兩行,分別描述感染後的主日誌和備份日誌。

每個日誌檔案的格式相同,均為乙個整數n (1<=n<=1000)(代表感染後的事件總數)和n 個不超過100,000的正整數(表示感染後各事件的時間戳)。

注意,感染後可能會出現時間戳完全相同的事件。

對於每組資料,輸出真實事件序列的最長可能長度。

1

9 1 4 2 6 3 8 5 9 1

6 2 7 6 3 5 1

3

解決方案:首先,在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,離平方還有一段距離。

code:

#include #include#includeusing namespace std;

const int maxn=1004;

int num1[maxn];

int num2[maxn];

int dp[maxn][maxn];

int main()

scanf("%d",&n2);

for(int i=1;i<=n2;i++)

memset(dp,0,sizeof(dp));

int mmax=0;

for(int i=1;i<=n1;i++)}}

if(dp[i][j]>mmax) mmax=dp[i][j];}}

printf("%d\n",mmax);

}return 0;

}

但是,這個演算法最關鍵的是,如果按照乙個合理的遞推順序,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)]的最大值。 

code:

#include #include#includeusing namespace std;

const int maxn=1004;

int num1[maxn];

int num2[maxn];

int dp[maxn][maxn];

int main()

scanf("%d",&n2);

for(int i=1; i<=n2; i++)

memset(dp,0,sizeof(dp));

int mmax=0;

int max=0;

for(int i=1; i<=n1; i++)

}printf("%d\n",mmax);

}return 0;

}

最長公共子串行 最長公共子串

1 最長公共子串行 採用動態規劃的思想,用乙個陣列dp i j 記錄a字串中i 1位置到b字串中j 1位置的最長公共子串行,若a i 1 b j 1 那麼dp i j dp i 1 j 1 1,若不相同,那麼dp i j 就是dp i 1 j 和dp i j 1 中的較大者。class lcs el...

最長公共子串行 最長公共子串

1.區別 找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。2 最長公共子串 其實這是乙個序貫決策問題,可以用動態規劃來求解。我們採用乙個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧 bab 和 caba 當然我們現在一眼就可以看出來最長公...

最長公共子串 最長公共子串行

子串要求連續 子串行不要求連續 之前的做法是dp求子序列 include include include using namespace std const int inf 0x3f3f3f3f const int mod 1000000007 string s1,s2 int dp 1010 10...