首页 > 其他 > 详细

P2308 添加括号(dfs记录dp路径)

时间:2020-04-16 15:32:14      阅读:58      评论:0      收藏:0      [点我收藏+]

传送门

\(一看肯定是区间DP(因为和和合并石子很相似,都要加n-1次)\)

\(转移方程为(其中he[i][j]是i到j的和)\)

\[dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+he[i][j]) \]

\(问题Ⅰ.如何输出括号\)

\(在转移的时候,我们可以用vis[i][j]来记录i到j合并的断点k,所以可以分别递归i至k和k+1至r\)

void dfs(int l,int r)
{
	if(l==r)	return;
	z[l]++,y[r]++;//记录左右括号 
	dfs(l,vis[l][r]);
	dfs(vis[l][r]+1,r);
}

那求中间和也是一样的道理。

void DFS(int l,int r)
{
	if(l==r)	return;
	DFS(l,vis[l][r]);
	DFS(vis[l][r]+1,r);
	cout<<he[l][r]<<" ";
}

完整代码

#include <bits/stdc++.h>
using namespace std;
int n,dp[22][22],a[22],he[22][22],vis[22][22];
int z[22],y[22];
void dfs(int l,int r)
{
	if(l==r)	return;
	z[l]++,y[r]++;//记录左右括号 
	dfs(l,vis[l][r]);
	dfs(vis[l][r]+1,r);
}
void DFS(int l,int r)
{
	if(l==r)	return;
	DFS(l,vis[l][r]);
	DFS(vis[l][r]+1,r);
	cout<<he[l][r]<<" ";
}
int main()
{
	cin>>n;
		memset(dp,20,sizeof(dp));
	for(int i=1;i<=n;i++)	cin>>a[i],dp[i][i]=0;
	for(int i=1;i<=n;i++)
	{
		int sumn=0;
		for(int j=i;j<=n;j++)
		{
			sumn+=a[j];
			he[i][j]=sumn;
		}
	}
	for(int l=2;l<=n;l++)
	for(int i=1;i+l-1<=n;i++)
	{
		int j=i+l-1;
		for(int k=i;k<=j-1;k++)
		{
			if(dp[i][j]>=dp[i][k]+dp[k+1][j]+he[i][j])
			{
				dp[i][j]=dp[i][k]+dp[k+1][j]+he[i][j];
				vis[i][j]=k;//在k点分割的 
			}
		}
	}
	dfs(1,n);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=z[i];j++)	cout<<"(";
		cout<<a[i];
		for(int j=1;j<=y[i];j++)	cout<<")";
		if(i!=n)	cout<<"+";
	}
	cout<<endl;
	cout<<dp[1][n]<<endl;
	DFS(1,n);
}

P2308 添加括号(dfs记录dp路径)

原文:https://www.cnblogs.com/iss-ue/p/12713034.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!