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

传送门

(一看肯定是区间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);
}
原文地址:https://www.cnblogs.com/iss-ue/p/12713034.html