1. 程式人生 > >NOIP2016提高組初賽(2)四、讀程序寫結果3、求最長回文子序列

NOIP2016提高組初賽(2)四、讀程序寫結果3、求最長回文子序列

所有 並且 names mes font esp mic abcd 大小

#include <iostream>
using namespace std;
int lps(string seq, int i, int j) {
int len1, len2;
if (i == j)//當i=j時,則此時掃描到的項是一定可以放入該回文子序列中並且對回文子序列的長度貢獻為1
return 1;
if (i > j)//當i>j時,即掃描到的左邊的數在右邊已經掃描過了,所以該項及往後的所有項都是已經掃描過的項,對回文子序列的長度貢獻為0
return 0;
if (seq[i] == seq[j])//當掃描到相同的字符時
return lps(seq, i + 1
, j - 1) + 2;//此時這兩個相同字符必定可以放入回文子序列中,故總計對回文子序列的長度貢獻為2 len1 = lps(seq, i, j - 1);//如果沒有掃描到相同字符,則此時有兩種情況,一種是此時的第i個字符對最長回文子序列的長度有貢獻 len2 = lps(seq, i + 1, j);//另一種是此時的第j個字符對最長回文子序列的長度有貢獻 if (len1 > len2)//比較上面兩種情況的回文子序列的長度大小,返回其中長度較大的回文子序列的長度 return len1; return len2; } int main() { string seq = "acmerandacm
";//給出字符串 int n = seq.size();//統計字符串的長度 cout << lps(seq, 0, n - 1) << endl;//計算最長回文子序列 return 0; }

輸出:_________

【一個計算最長回文子序列的例程,值得一背】

  首先是關於掃描的事項

    一是可能有的時候會比較難理解為什麽當 i == j 時對回文子序列的貢獻為1,例如:abcda,除了頭尾的a對回文子序列的貢獻為2,中間的bcd不管是怎麽掃描,對於a _ a 這個回文子序列來講,b或c或d是肯定可以填入其中的空格中的,所以對回文子序列的貢獻為1

    二是要明白遞推公式,除了掃描到相等的項時一定是最長回文子序列中的一部分且對其貢獻為2外,那麽,當掃描到不相等的兩個項時,該怎麽想呢?

    對於不相等的兩個項 [ i ] [ j ] ,其回文子序列的長度無非兩種情況

    ①先掃描 [ i ][ j-1 ] 所得的回文子序列長度比較長  ②先掃描 [ i-1 ][ j ] 所得的回文子序列長度比較長

    那麽我們分別遞歸兩種情況,然後比較這兩種情況中哪一個回文子序列更長,進而可以求出最長的回文子序列啦

  然後是一些關於閱讀程序的心得

    首先,讀程序建議從主程序開始讀,先大概了解程序後在看函數往往有奇效(反正我是這樣感覺的)

     其次,當你閱讀程序時,不建議只是掃一遍,最好是能把相應步驟的關鍵點和一些比較難一眼看出來意義的段落加上註釋(可能是因為我還是一個蒟蒻才需要這樣做吧......)

     最後,當你對一段程序迷惑時,請你:跟著程序跑一遍-->用編譯器再跑一遍-->對於自己有疑慮的點,請造出來然後用編譯器跑一遍

     總之,多動手。

     學OI就是一個積累和學習的過程,碼得越多,看的越多,就懂得越多。

NOIP2016提高組初賽(2)四、讀程序寫結果3、求最長回文子序列