经典DP题啊,看着黑书学的。
虽然它作为DP来讲,算是很水吧,不过说下我的理解吧。
枚举步长,相隔0个字符的两个字符,相隔1个的,相隔2个的。。等等。
假设在求相隔N个的字符时的两个字符的情况时,他俩中间的所有情况都已经考虑到了,所以只需要把他划分一下(划分成,(1,x )+ (x,N)然后用小区间去更新大区间,而这些小区间都是已经匹配了的。
明显突出了最优子结构以局部推整体。
很神奇~
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
const int MAX = 110;
char s[MAX];
int dp[MAX][MAX];
int main()
{
int ncases;
scanf("%d",&ncases);
while( ncases-- )
{
scanf("%s",s);
memset(dp,0,sizeof(dp));
int n = strlen(s);
for(int i=0; i<n; i++)
dp[i][i] = 1;
for(int i=1; i<n; i++)
for(int k=0; k<n-i; k++)
{
int j = i+k;
dp[k][j] = INT_MAX;
if( s[k] == '(' && s[j] == ')' || s[k] == '[' && s[j] == ']' )
dp[k][j] = min(dp[k][j],dp[k+1][j-1]);
else
if( s[k] == '(' || s[k] == '[' )
dp[k][j] = min(dp[k][j],dp[k+1][j]+1);
else
dp[k][j] = min(dp[k][j],dp[k][j-1]+1);
for(int p=k; p<j; p++)
dp[k][j] = min(dp[k][j],dp[k][p]+dp[p+1][j]);
}
printf("%d\n",dp[0][n-1]);
}
return 0;
}
刚看了nyist的标程,只需要一个判断就行了 T T 。。。也是。。。
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
const int MAX = 110;
char s[MAX];
int dp[MAX][MAX];
int main()
{
int ncases;
scanf("%d",&ncases);
while( ncases-- )
{
scanf("%s",s);
memset(dp,0,sizeof(dp));
int n = strlen(s);
for(int i=0; i<n; i++)
dp[i][i] = 1;
for(int i=1; i<n; i++)
for(int k=0; k<n-i; k++)
{
int j = i+k;
dp[k][j] = INT_MAX;
if( s[k] == '(' && s[j] == ')' || s[k] == '[' && s[j] == ']' )
dp[k][j] = min(dp[k][j],dp[k+1][j-1]);
for(int p=k; p<j; p++)
dp[k][j] = min(dp[k][j],dp[k][p]+dp[p+1][j]);
}
printf("%d\n",dp[0][n-1]);
}
return 0;
}