题意:有一个含'(' 和')'的字符串,每次操作可以将左括号变为右括号或者右括号变为左括号。问至少要变多少次才可以使得序列括号匹配。
思路:dp[i][j]表示[i,j]变为括号匹配的序列最小操作次数。dp[i][j]可以由dp[i+1][j-1]转移过来,或者枚举中间断开点由dp[i][k] + dp[k+1][j]转移过来。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007
const int maxn = 109;
LL f[maxn][maxn];
char s[maxn];
int T;
int main()
{
cin>>T;
getchar();
while(T--)
{
int len;
scanf("%d",&len);
getchar();
gets(s+1);
Clean(f,0);
rep(L,1,len)
{
rep(i,1,len-L+1)
{
int j = i + L - 1;
f[i][j] = inf;
if ( i == j ) continue;
f[i][j] = min( f[i][j] , f[i+1][j-1] + ( s[i]=='('?0:1 ) + ( s[j]==')'?0:1 ) );
rep(k,i,j-1)
f[i][j] = min( f[i][j] , f[i][k] + f[k+1][j] );
}
}
printf("%lld\n",f[1][len]);
}
return 0;
}