其他分享
首页 > 其他分享> > 区间dp

区间dp

作者:互联网

练习一下区间dp,总结一下题型

括号配对问题 Brackets Sequence


链接:https://172.16.79.125/contest/view.action?cid=831#problem/A

题意:给一串括号序列。依照合法括号的定义,加入若干括号,使得序列合法。

一道典题,思路是括号配对加上路径回溯,找出输入的所有不配对单括号,在输出时将其补充成完整括号对即可

括号配对

求序列配对的括号量,使用三层循环,前两层枚举长度和起点,然后要注意括号配对时更新dp值。由于合法的括号对都是嵌套或者并列的,所以第三层的枚举中间点只能帮我们解决括号的并列,但是不能解决括号的嵌套,所以我们还要自己加入判断,即当该区间的左右端点括号匹配时,dp[l][r]=dp[l+1][r-1]+1

路径回溯

这个也是典型,有两种方法,一种是不开辟数组,通过原来的dp转移方程来递归,另一种是开一个数组(一般dp过程可以简化数组维度,但路径回溯不可以,不过少部分题也可以),这个数组用来记录前驱(就是由谁更新了它),然后层层访问前驱即可。
以前写背包的路径回溯,两种方法都比较简单,现在看区间dp,感觉第二种好用点。区间dp由于第三层循环的存在,所以两种方法都会麻烦一点,第一种得遍历中间点,第二种得递归左区间和右区间。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 1e2+10 , M = N<<1,mod=1e9+7;
typedef long long LL;
typedef pair<int,int> PII;
//#define x first 
//#define y second

//int h[N],e[M],ne[M],idx;
//
//void add(int a,int b)
//{
//	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
//}

struct Node
{
	int l1,r1;
	int l2,r2;
};

char s[N];

int f[N][N];

Node path[N][N];

int st[N];

void dfs(int l,int r)    //路径回溯
{
	Node t =path[l][r];
	if(t.l1==l+1&&t.r1==r-1) 
	{
		st[l]=st[r]=1;
		dfs(l+1,r-1);
	}
	else if((t.l1|t.l2|t.r1|t.r2)==0) return;    //记得要加边界条件
	else 
	{
		dfs(t.l1,t.r1);
		dfs(t.l2,t.r2);
	}
}

int check(int l,int r)    //检查括号是否匹配
{
	if(s[l]=='('&&s[r]==')'||s[l]=='['&&s[r]==']') return 1;
	return 0;
}

void deal(char c)    //补全括号
{
	if(c=='('||c==')') cout<<"()";
	else if(c=='['||c==']') cout<<"[]";
}

void solve()        //区间dp
{
	cin>>s+1;
	int size=strlen(s+1);
	for(int len=2;len<=size;len++)
		for(int r=len;r<=size;r++)
		{
			int l=r-len+1;
			if(check(l,r))      //额外的判断条件
			{
				Node& t =path[l][r];
				if(f[l][r]<f[l+1][r-1]+1) f[l][r]=f[l+1][r-1]+1,t.l1=l+1,t.r1=r-1;
			}
			
			for(int k=l;k<r;k++)
			{
				Node& t =path[l][r];
				int sum=f[l][k]+f[k+1][r];
				if(sum>f[l][r]) 
				{
					f[l][r]=sum;
					t.l1=l,t.r1=k;
					t.l2=k+1,t.r2=r;
				}
			}
		}
	
	dfs(1,size);
	
	for(int i=1;i<=size;i++)
	{
		if(!st[i]) deal(s[i]);
		else cout<<s[i];
	}
	cout<<'\n';
	
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
//	int T;
//	cin>>T;
//	while(T--) 
	solve();
}

乡村邮局问题-Post Office(POJ-1160)

标签:r1,int,dfs,括号,l1,区间,dp
来源: https://www.cnblogs.com/Pleaf/p/16284346.html