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的正整數(表示感染後各事件的時間戳)。
注意,感染後可能會出現時間戳完全相同的事件。
對於每組資料,輸出真實事件序列的最長可能長度。
19 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...