把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

 

posted @ 2018-08-13 14:40  Starlight_Glimmer  阅读(12)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end