Brackets sequence UVA - 1626【dp+非常坑的輸入輸出】

紫書P278-279 例9-10

分析

很容易想到定義dp[i][j]爲s[i]~s[j]最少需要添加多少個括號

邊界

  1. 串爲空時,dp[i+1][i]=0
  2. 單個串時,dp[i][i]=1

轉移:

  1. 如果s[i]與s[j]匹配,轉移到dp[i+1][j-1]
  2. 枚舉斷點,轉移到dp[i][k]+dp[k+1][j]

注意:無論該區間是否滿足第一條,都要去嘗試轉移第二條,否則“[][]”會轉移到“][”,計算出來2,然而答案是0

這道題要輸出方案,利用遞歸輸出

然後,重點來了

  1. 組數T後面有一個換行,要用一個getchar()讀掉 而scanf("%d\n",&T); 我WA了
  2. 輸入串可能是空串,所以不能用scanf,要用fgets或gets
  3. gets不夠優秀(安全),所以被Uva搞掉了,會編譯錯誤
  4. fgets會在末尾保留一個換行符,所以求長度的時候要-1
  5. 輸入時,每兩組數據之間有一個空行,T和第一組數據間也有一個空行
  6. 輸出時,每兩組數據之間有一個空行,最後一組數據沒有

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章