题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=15
这道题我已经看了不下5遍了, 每次看了都是没思路, 这次再看还是没思路,但还是硬着头皮往下做了, 网上百度解题思路,看别人的博客, 终于看出来点门路了, 又想了许久, 又向学长求教了一下, 学长说是区间dp,然后我就全明白了, 区间dp以前学过了, 竟让一点也没有想到, 瞬间感觉还是很菜、、、
dp(i, j) 表示从第i个字符到第j个字符完全配对需要最少添加的字符个数,
分两种情况,
(1)当i、j字符配对时,dp(i,j) = dp(i+1, j-1);
(2) 当i、j字符不配对时,就枚举i,j之间所有的位子,dp(i,j) = min(dp(i,k)+dp(k+1, j), dp(i,j));
初始化时, dp[i][i] = 1; 代表当串长度为一时,最少需要一个字符就能配对了;当i,j相差为一且能相配对时,dp(i,j) = dp(i+1,j-1), 所初始化时dp[i+1][i] = 0, 其他的为最大就可以了。
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 100 + 10;
int dp[maxn][maxn];
char s[maxn];
bool match(char a, char b)
{
if(a=='(' && b==')')
return true;
else if(a=='[' && b==']')
return true;
return false;
}
int solve(int n)
{
for(int i = 0; i < n; i++)
{
dp[i][i] = 1;
dp[i+1][i] = 0;
}
for(int i = n-2; i >= 0; i--)
for(int j = i+1; j < n; j++)
{
dp[i][j] = n;
if(match(s[i], s[j]))
dp[i][j] = min(dp[i][j], dp[i+1][j-1]);
for(int k = i+1; k < j; k++)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
}
return dp[0][n-1];
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s", s);
int n = strlen(s);
printf("%d\n", solve(n));
}
return 0;
}