题意给你一串由括号组成的串,输出一个方案把括号匹配好,要求方案的长度要最短。
记录路径path[i][j],状态dp[i][j]
如果str[i]与str[j]匹配那么dp[i][j]=dp[i+1][j-1],path[i][j]=-1 然后枚举断点找出最小值path[i][j]=k 对应断点
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
typedef long long lld;
typedef unsigned int ud;
#define oo 0x3f3f3f3f
#define maxn 205
int dp[maxn][maxn];
int path[maxn][maxn];
char str[102];
bool match(char l, char r)
{
if (l == '('&&r == ')')
return true;
if (l == '['&&r == ']')
return true;
return false;
}
void Print(int i, int j)
{
if (i > j)
return;
if (i == j)
{
if (str[i] == '(' || str[i] == ')') printf("()");
else printf("[]");
}
else
{
if (path[i][j] == -1)
{
printf("%c", str[i]);
Print(i + 1, j - 1);
printf("%c", str[j]);
}
else
{
Print(i, path[i][j]);
Print(path[i][j] + 1, j);
}
}
}
int main()
{
int T;
scanf("%d", &T); getchar();
while (T--)
{
getchar();
gets(str + 1);
int n = strlen(str + 1);
if (n == 0)
{
printf("\n");
continue;
}
//注意初始化方式,这是易错点,如果统一赋值为最大然后再把i==j的赋值为1会出错 这个数据不会过()()
//为什么呢?如果这样赋值,那么在dp的第一次循环中()即使匹配了,但是此时dp[i+1][j-1]的值是无穷大,那么*(1)语句就跳过了
//跳过了*(1)语句那么最小值为0就跳过了,结果肯定会错。
for (int i = 1; i <= n;i++)
for (int j = 1; j <= n; j++)
{
if (j < i)
dp[i][j] = 0;
else if (j == i)
dp[i][j] = 1;
else
dp[i][j] = oo;
}
memset(path, -1, sizeof path);
for (int L = 2; L <= n; L++)
for (int i = 1; i + L - 1 <= n; i++)
{
int j = i + L - 1;
if (match(str[i], str[j]))
{
if (dp[i][j] > dp[i + 1][j - 1])//*(1)
{
dp[i][j] = dp[i + 1][j - 1];
path[i][j] = -1;
}
}
for (int k = i; k < j; k++)
if (dp[i][j] > dp[i][k] + dp[k + 1][j])
{
dp[i][j] = dp[i][k] + dp[k + 1][j];
path[i][j] = k;
}
}
Print(1, n);
puts("");
if (T)
puts("");
}
return 0;
}