POJ 1159 (DP)
題目:http://poj.org/problem?id=1159
思路:
找出原串的最長回文子串,當然這里說的回文子串可以不連續。用原串的長度減去最長回文子串的長度即可得出結果。
設原串a[5001],它的反串為b[5001],求出a和b的最長公共子串的長度(可以不連續),即為回文子串的長度。再用原串長度減去回文子串的長度即可。
用動態規劃求公共子串的長度,m[5001][5001]打表。m[i][j]表示原串a第1個到第i個和反串b第1個到第j個的最長公共子串的長度。所以有兩種情況:
(1)當a[i] = b[j]時,m[i][j]=m[i-1][j-1] + 1;
(2) a[i] != b[j]時,m[i][j]=max(m[i-1][j],m[i][j-1])。
?所以m[len][len]就是最長公共子串的長度。(len為原串的長度)
?
?
算法正確性證明:
比如abcdb,最長回文串是bcb或bdb,長度是3,5-3=2,所以只需插入2個即可。為什么呢???
??? 因為回文串有兩種形式aba或者abba,我們暫且把后面那兩個b看成是一個,這個沒關系的,便于解釋。那么一個字符串就分成了兩類字符了,一個是回文串,一個是非回文串,假設把回文串的中間那個字符記成b,那么b左邊的非回文串和b右邊的非回文串就不可能有交集(如果有,那交集部分就會歸并到回文串里),所以只需要在左邊對稱位置插入b右邊的非回文字符,在右邊插入b左邊的非回文字符。所以要插入的字符個數就是非回文字符的個數,非回文字符就是回文字符串對原字符串的補集,故原串長度減去回文串長度即可得解。
?
代碼:
?
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 5001char a[N],b[N];unsigned short m[N][N];int main() {int len,i,j,t;while(scanf("%d",&len) != EOF ){scanf("%s",a); t = len -1;for(i = len-1; i >= 0 ; --i)b[t-i] = a[i] ;for(i = 1 ; i <= len ; ++i)for(j = 0 ; j < i ; ++j) m[i][j] = m[j][i] = 0;for(i = 0 ; i <= len ; ++i)m[i][i] = 0;for(i = 1 ; i <= len ; ++i){for(j = 1 ; j <= len ; ++j){if(a[i-1] == b[j-1])m[i][j] = m[i-1][j-1] + 1;elsem[i][j] = m[i-1][j] > m[i][j-1] ? m[i-1][j]:m[i][j-1];}}printf("%d\n",len - m[len][len]);} // system("pause");return 0; }?
?
開始用 int m[N][N]; 超內存了!用unsigned short 就AC了。
?
看discuss,人家用滾動數組!汗,落伍了。第一次聽說這玩意,于是誠信學習了啊!
?
先貼個最簡單的滾動數組的應用:(求Fabonacci數列的第100個數)
int d[3];
d[0]=1;d[1]=1;
for(i=2;i<100;i++)
d[i%3]=d[(i-1)%3]+d[(i-2)%3];
printf("%d",d[99%3]);
注意上面的運算,我們只留了最近的3個解,數組好象在“滾動?一樣,所以叫滾動數組。
好了,這個題就可以用滾動數組+DP AC了。用一個二位的數組m[2][N]。列可以往后展開,行不停的滾動,
滾動方式: i%2,(i-1)%2
代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 5001unsigned short m[2][N]; char a[N],b[N];int main() {int len,i,j,t;while(scanf("%d",&len) != EOF ){scanf("%s",a); t = len -1;for(i = len-1; i >= 0 ; --i)b[t-i] = a[i] ;for(i = 0 ; i <= len ; ++i) m[0][i] = m[1][i] = 0;for(i = 1 ; i <= len ; ++i){for(j = 1 ; j <= len ; ++j){if(a[i-1] == b[j-1])m[i%2][j] = m[(i-1)%2][j-1] + 1;elsem[i%2][j] = m[(i-1)%2][j] > m[i%2][j-1] ? m[(i-1)%2][j]:m[i%2][j-1];}}printf("%d\n",len - m[len%2][len]); } //system("pause");return 0; }?
?
?
?
?
?
轉載于:https://www.cnblogs.com/HpuAcmer/archive/2012/05/03/2481323.html
總結
以上是生活随笔為你收集整理的POJ 1159 (DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Coursera NLP 笔记02
- 下一篇: 进入社会,我们要做哪些准备?