题意分析:
给字符串添加最少的字符让其成为回文串。
解题思路:
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; }