紫書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;
}