poj1141 括号序列 dp

本题难在输出括号序列,dp是比较简单的

dp[ i ][ j ] 存储 i~j 这段括号序列需要添加的括号数,决策有两种,对dp[ i ][ j ],

       (1).若i 与j 是匹配的,只需将i+1~j-1这段变成合理的括号序列;

       (2).取i~j中间的k, 使i~p 和 p+1~j 均为合理的括号序列。

状态转移方程:dp[ i ][ j ] = MIN( dp[ i + 1 ][ j - 1 ], MIN(dp[ i ][ k ]+dp[ k+1 ][ j ]) ), 其中i <= p < j.。

用记忆化搜索和string记录,时间效率低 。

测试数据的输入有空串,注意输入输出,之前cin  >>  str; cout << ans[0][len-1]; 提交一直OLE, 很少见的错误, 改成现在这样就A了 

#include <iostream>
#include <string>
using namespace std;

const int M = 105;

char str[M];
int dp[M][M];
string ans[M][M];

int Search(int l, int r)
{ 
    int i, min = 10000000; 
	
    if(dp[l][r] != -1) return dp[l][r];
	if(l > r) return 0;
	if(l == r) {
		if(str[l] == '(' || str[l] == ')') ans[l][r] = "()";
		else ans[l][r] = "[]";
		return dp[l][r] = 1;
	}
	
	int mark = 0, tmp;
	int id;
	for(i = l; i < r; i++){
		tmp = Search(l, i) + Search(i+1, r);
		if(tmp < min){
			id = i;
			min = tmp;
			mark = 2;
		}
	}
	if(( str[l] == '(' && str[r] == ')' ) || ( str[l] == '[' && str[r] == ']' ) ){
		tmp = Search(l+1, r-1);
		if(min > tmp) {
			min = tmp;
			mark = 1;
		}
	}
	if(mark == 1) ans[l][r] = str[l]+ans[l+1][r-1]+str[r];
	else ans[l][r] = ans[l][id]+ans[id+1][r];
	
	return dp[l][r] = min;
}
int main()
{
	int i, j;
	memset(dp, -1, sizeof(dp));
	cin >> str+1;
	int len = strlen(str+1);
	for(i = 1; i <= len; i++)
		for(j = i; j <= len; j++)
			ans[i][j] = ans[j][i] = "";
	Search(1, len);
	cout << ans[1][len] << endl;		
	//system("pause");
	return 0;
}

 

代码2:自底向上的递推,记录路径,递归输出,不用string得到答案,效率高了,0ms

#include <iostream>
using namespace std;

#define M 105

int dp[M][M], path[M][M];
char str[M];
int n;

void output(int i, int j)
{
	if(i == j){
	    if(str[i] == '(' || str[i] == ')')
			printf("()");
		else printf("[]");
		return;
	}
    if(path[i][j] == -1){
		if(i+1 == j)
	       printf("%c%c", str[i], str[j]);
		else{
		   printf("%c", str[i]);
		   output(i+1, j-1);
		   printf("%c", str[j]);
		}
	}
	else{
	     output(i, path[i][j]);
		 output(path[i][j]+1, j);
	}
}

int main()
{
   int i, j, l, k;
   
   gets(str);
   n = strlen(str);
   if(n == 0) { 
	   printf("\n");
	   return 0;
   }
   for(l = 1; l <= n; l++){
	   for(i = 0; i+l-1 < n; i++){
	       j = i+l-1;
		   if(i == j) dp[i][j] = 1;
		   else {
			   dp[i][j] = INT_MAX;
			   if( (str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']') ){
				   if(i+1 == j) dp[i][j] = 0;
				   else {
					   if(dp[i][j] > dp[i+1][j-1])
					       dp[i][j] = dp[i+1][j-1];
				   }
				   path[i][j] = -1;
			   }
			   for(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;
				   }
		   }
	   }
   }
   output(0, n-1);
   printf("\n");
  // system("pause");
   return 0;
}


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值