poj1141Brackets Sequence 区间dp+输出路径

最近看区间dp也看了好几题了,终于知道了大概的思路,当然只是大概……只会套模板,稍微变一变就GG了,还是没真正理解……

先上区间dp的超级简单好写的模板

for(l=0;l<n;l++)    //枚举区间长度

  for(i=0,j=i+l;j<n;j++)  //枚举头尾指针

    { 如果可以更新或初始化,更新或初始化dp[i][j],

    for(k=i;k<j;k++)             //虽然我有种预感,有的时候这边可能会变形,不一定就是两个区间合并,不知道这种预感对不对

      比较dp[i][j]和dp[i][k]+dp[k+1][j],如果能更新的话更新

     }    

关于区间dp的理解:dp[l][r]记录的是l区间到r区间的最优解,那么就要保证l~r之间的小区间也是最优解,这样才可以由子问题堆砌大问题,同时要保证子问题可以合并成大问题(上次陕师大校赛的那道蜘蛛纸牌一开始想的是就按给定的牌顺序进行区间dp,怎么都觉得两个子区间不能合并,还好有一神来解救我告诉我按自然顺序进行dp,真是智障了……



放一道poj上的裸题


Brackets Sequence
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 29473 Accepted: 8389 Special Judge

Description

Let us define a regular brackets sequence in the following way: 

1. Empty sequence is a regular sequence. 
2. If S is a regular sequence, then (S) and [S] are both regular sequences. 
3. If A and B are regular sequences, then AB is a regular sequence. 

For example, all of the following sequences of characters are regular brackets sequences: 

(), [], (()), ([]), ()[], ()[()] 

And all of the following character sequences are not: 

(, [, ), )(, ([)], ([(] 

Some sequence of characters '(', ')', '[', and ']' is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 ... an is called a subsequence of the string b1 b2 ... bm, if there exist such indices 1 = i1 < i2 < ... < in = m, that aj = bij for all 1 = j = n.

Input

The input file contains at most 100 brackets (characters '(', ')', '[' and ']') that are situated on a single line without any other characters among them.

Output

Write to the output file a single line that contains some regular brackets sequence that has the minimal possible length and contains the given sequence as a subsequence.

Sample Input

([(]

Sample Output

()[()]


题意:给定原括号序列,让你添加最少的括号使其完全匹配,输出最小的匹配方案

思路:对于每个记录i~j最小添加次数的dp[i][j],如果i与k本身就匹配,那么dp[i][j]可以转变为dp[i+1][j-1](注意:这里转变后不一定是最优解,比如()()这样的,不转移不要添加,转移后就要添加两个了),接着进行小区间的枚举,如果dp[i][j]>dp[i][k]+dp[k+1][j]那么就进行更新。

上面这些没有难度,套模板就行了,难点是要输出匹配后的方案。

我们可以发现,对于每一组括号,总是先输出总是先输出外围的,再输出内部的,这不难想到进行递归(好吧,智障的我在看题解之前完全想不到)输出。我们可以在求dp数组时同时记录下每个区间的划分端点是什么,如果没有划分端点,那么这个区间就直接可以转为i+1~j-1区间,如果有划分端点,那么从端点处进行二分输出。


代码如下

#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
int i,j,k,m,n,l;
 char s[150];
 int dp[120][120];
 int path[120][120];
void output(int l,int r)
{   if(l>r)return;
	if(l==r)
	{if(s[r]=='('||s[r]==')')printf("()");
	  else printf("[]");
	 return;
	}
	else
	if(path[l][r]==-1)
	{printf("%c",s[l]);
	 output(l+1,r-1);
	 printf("%c",s[r]);
	}
	else
	{
		output(l,path[l][r]);
		output(path[l][r]+1,r);	
	}
	return;
}

int main()
{
 
 while(gets(s))
 {
   n=strlen(s);
   memset(dp,0,sizeof(dp));  //注意,当区间长度为2时,()这样的dp[i][i+1]就正好赋值为0 
   for(i=0;i<=n;i++)dp[i][i]=1;
   for(l=1;l<n;l++)
   {for(i=0,j=i+l;j<n;i++,j++)
      { dp[i][j]=0x1f1f1f;
      	if(s[i]=='(' && s[j]==')' || s[i]=='[' && s[j]==']' && 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][k]+dp[k+1][j]<dp[i][j])
		    {dp[i][j]=dp[i][k]+dp[k+1][j];
			 path[i][j]=k;	
				}	
	  }
   	  
		}
	//printf("%d\n",dp[0][n-1]);
	/*for(i=0;i<n;i++)
	 for(j=0;j<n;j++)
	  printf("i:%d  j:%d  :%d\n",i,j,dp[i][j]);*/	
	output(0,n-1);	 
	printf("\n");	
}
	 return 0;	
 } 

哎,吐槽一下poj,这个题神一般的莫名wa了两发,点开discuss才知道原来输入里有空行,不能用scanf输入……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值