POJ 1141 Brackets Sequence(JAVA版)

本文介绍了一种解决括号序列匹配问题的动态规划算法,通过分析字符串中的括号配对情况,实现最少添加字符使序列合法的目标。文章详细解释了状态转移方程,并提供了完整的AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ 1141 Brackets Sequence

题目大意:给定一连串只包含"("、")"、"["、"]"的字符串,求至少添加多少个字符才能使该字符串变成一个规则的序列,并输出添加后的序列,这题一个字符串可能有不止一个答案,所以是Special Judge,不用担心(话说,当初因为这个纠结了好久)。

思路如下:对一个给定的字符串拆分为字符数组后,先对首尾两端进行比较,看看他们是否匹配,若匹配,则可以先认为dp[i][j]=dp[i+1][j-1],dp[i][j]代表的是从 i 到 j 的最小字符串匹配量。接下来就循环找分割点,即使dp[i][j]<dp[i][k]+dp[k+1][j]的 k 值,意思是在某点可能出现a[j]与a[k],a[k+1]与a[j]这两对任意一对以上相互匹配的情况使最小添加量减少(分析到这步就能确定是动态规划了)只要记得用note[i][j]数组记录分割点即可,最后再回溯。这样一来就能得到:

状态转移方程:dp[i][j]=Math.min(dp[i][j], dp[i][k]+dp[k+1][j]),这是在首尾不相互匹配的情况下的(首尾的问题,加个 if 即可)

AC代码:

import java.util.Scanner;

public class Main
{
	static Scanner scan=new Scanner(System.in);
	public static void print(int l, int r, int[][] note, char[] a)
	{
		if(l>r)return;//左坐标大于右,跳出
		else
		{
			if(note[l][r]==-1)//没有分割点
			{
				if(l==r)//考虑左右坐标相等的情况
				{
					if(a[l]=='(' || a[l]==')')
						System.out.print("()");
					if(a[l]=='[' || a[l]==']')
						System.out.print("[]");
				}
				else
				{
					System.out.print(a[l]);
					print(l+1, r-1, note, a);
					System.out.print(a[r]);
				}
			}
			else//分割点派上用场了~
			{
				int temp=note[l][r];
				print(l, temp, note, a);
				print(temp+1, r, note, a);
			}
		}
		return;
	}
	
	public static void main(String[] args)
	{
		while(scan.hasNext())
		{	
			String str=scan.next();
			int len=str.length()+1;
			
			char a[]=new char[len];
			for(int i=1;i<len;i++)
				a[i]=str.charAt(i-1);
			
			int dp[][]=new int[len][len];//dp[i][j]表示从 i 到 j 需要的最小(括号)添加量
			int note[][]=new int[len][len];//note[i][j]记录i到 j 区间的分割点,即添加位置,如不需添加,则为-1
			
			for(int i=1; i<len; i++)
			{
				dp[i][i]=1;//dp[i][i]天生需要一个添加量
				for(int j=1; j<len;j++)
					note[i][j]=-1;//初始化~先默认所有位置都不需要分割
			}
			
			for(int i=1; i<len; i++)
			{
				for(int j=1; j+i<len; j++)
				{
					dp[j][j+i]=0x7fffffff;
					if((a[j]=='('&&a[j+i]==')') || (a[j]=='['&&a[j+i]==']'))//dp[j][j+i]的首尾两项相互匹配的话
						dp[j][j+i]=dp[j+1][j+i-1];//那么dp[j][j+i]的首尾两项就不会为总体增加(括号)添加量
		
					for(int k=j; k<j+i; k++)//这个就是用来寻找合适的分割点的了(如果有的话)
						if(dp[j][j+i]>dp[j][k]+dp[k+1][j+i])//比较
						{
							dp[j][j+i]=dp[j][k]+dp[k+1][j+i];
							note[j][j+i]=k;//记录分割点
						}
				}
			}
			print(1, len-1, note, a);//开始回溯,打印
		}
		System.out.println();//ps:这道题只读一个数据,还有个空行,输入空行,就要输出空行。hasNext()不读取空行,不进入循环,当时在这里卡了很久,偏偏没想到这茬~~。。。
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值