紫书P278-279 例9-10
分析
很容易想到定义dp[i][j]为s[i]~s[j]最少需要添加多少个括号
边界:
- 串为空时,dp[i+1][i]=0
- 单个串时,dp[i][i]=1
转移:
- 如果s[i]与s[j]匹配,转移到dp[i+1][j-1]
- 枚举断点,转移到dp[i][k]+dp[k+1][j]
注意:无论该区间是否满足第一条,都要去尝试转移第二条,否则“[][]”会转移到“][”,计算出来2,然而答案是0
这道题要输出方案,利用递归输出
然后,重点来了
- 组数T后面有一个换行,要用一个getchar()读掉 而scanf(“%d\n”,&T); 我WA了
- 输入串可能是空串,所以不能用scanf,要用fgets或gets
- gets不够优秀(安全),所以被Uva搞掉了,会编译错误
- fgets会在末尾保留一个换行符,所以求长度的时候要-1
- 输入时,每两组数据之间有一个空行,T和第一组数据间也有一个空行
- 输出时,每两组数据之间有一个空行,最后一组数据没有
Uva的格式是 真·漂(恶)亮(心) _(:з」∠)_
//被输入输出卡qwq
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define LL long long
#define MAXN 110
#define INF 0x3f3f3f3f
char s[MAXN];
int dp[MAXN][MAXN];
bool mch(int x,int y)
{
if((s[x]=='('&&s[y]==')')||(s[x]=='['&&s[y]==']'))
return 1;
return 0;
}
void print(int i,int j)
{
if(i>j) return ;
if(i==j)
{
if(s[i]=='('||s[i]==')') printf("()");
else printf("[]");
return ;
}
int ans=dp[i][j];
if(mch(i,j)&&ans==dp[i+1][j-1])
{
printf("%c",s[i]);
print(i+1,j-1);
printf("%c",s[j]);
return ;
}
for(int k=i;k<j;k++)
if(ans==dp[i][k]+dp[k+1][j])
{
print(i,k);
print(k+1,j);
return ;
}
}
int main()
{
int T;
scanf("%d",&T);
getchar();
while(T--)
{
memset(dp,0,sizeof(dp));
fgets(s,MAXN,stdin);//2组数据之间有一个空串
fgets(s,MAXN,stdin);
//输入可能是空串
int n=strlen(s)-1;
for(int i=0;i<n;i++)
dp[i+1][i]=0,dp[i][i]=1;//空串为0,单个字符为1
for(int i=n-2/*n-1已初始化*/;i>=0;i--)//倒序为了转移时dp[i+1][j-1]和dp[k+1][j]已经被计算
for(int j=i+1;j<=n-1;j++)
{
dp[i][j]=INF;
if(mch(i,j)) dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
for(int k=i;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
print(0,n-1);
puts("");
if(T) puts("");//2组数据间隔一个空行 漂(e)亮(xin)的格式
}
return 0;
}