题目链接:
[POJ 1159]Palindrome[DP]
题意分析:
给字符串添加最少的字符让其成为回文串。
解题思路:
dp[i][j]代表,区间[i,j]变成回文要插入的最少字符数。如果s[i] == s[j],那么dp[i][j] = dp[i + 1][j - 1];否则,dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + 1(由已经构成回文的区间添加一个字符)。本题int,5000*5000大概90000k,所以使用short降低一半,而且short最大值为3e4左右,比最大可能插入值要大,所以可行
个人感受:
状态想好了,就是不知道怎么写循环= =,最后不得不用上记忆化搜索。。。。。然后边界条件没处理好,让我太迷了。。。。。
具体代码如下:
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define si short
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;
const int MAXN = 5e3 + 100;
si mmin(si a, si b) {
return a < b ? a : b;
}
si dp[MAXN][MAXN];
char s[MAXN];
si dfs(si l, si r) {
si &ret = dp[l][r];
if (ret >= 0) return ret;
if (l + 1 == r) return ret = (s[l] != s[r]);
if (l == r) return ret = 0;
if (s[l] == s[r]) ret = dfs(l + 1, r - 1);
else ret = mmin(dfs(l + 1, r), dfs(l, r - 1)) + 1;
return ret;
}
int main()
{
int n;
while (~scanf("%d%s", &n, s)){
memset(dp, -1, sizeof dp);
printf("%d\n", dfs(0, n - 1));
}
return 0;
}
16/03/14 update:补上循环写法:比记忆化快好多。。。。
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define si short
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;
const int MAXN = 5e3 + 100;
si mmin(si a, si b) {
return a < b ? a : b;
}
si dp[MAXN][MAXN];
char s[MAXN];
int main()
{
int n;
while (~scanf("%d%s", &n, s)){
for (int i = n - 1; i >= 0; --i) {
dp[i][i] = 0;
for (int j = i + 1; j < n; ++j) {
if (s[i] == s[j] && i + 1 < j) dp[i][j] = dp[i + 1][j - 1];
else if (s[i] == s[j]) dp[i][j] = 0;
else dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + 1;
}
}
printf("%d\n", dp[0][n - 1]);
}
return 0;
}