区间dp【洛谷P1040】

照例送上题目链接:https://www.luogu.org/problemnew/solution/P1040

这个题目是个区间dp(为什么会在洛谷的dfs里面,我也不知道啊)

dfs啊呸,区间dp,顾名思义,就是在一段区间[l,r]上的dp(我在说什么乱七八糟的,划掉划掉)。

乍一看这个题目,看似无从下手(可能只有我自己无从下手),其实仔细一分析,题目要,求最大值,我们就直接枚举树根,然后把左右儿子按照题目要求的操作一波就好啦。

dp方程直接给出来了,很好理解  dp[i][j] = max(dp[i][j],dp[i][k-1]*dp[k+1][j]+dp[k][k]) ,其中dp[i][j]表示节点i到节点j的最大值。

1.首先枚举区间长度。

2.枚举左端点。

3.枚举根

先序遍历就直接递归输出root就好啦(先访问根,然后输出左边,然后输出右边)。

还是直接看代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50;
ll dp[maxn][maxn];
ll root[maxn][maxn];
void init()
{
	memset(dp,0,sizeof(dp));
	memset(root,0,sizeof(root));
}
void print(int l,int r)
{
	if(l>r)
	{
		return;
	}
	cout<<root[l][r]<<" ";
	if(l==r)
	{
		return;
	}
	print(l,root[l][r]-1);
	print(root[l][r]+1,r);
}
int main()
{
	int n;
	while(cin>>n)
	{
		for(int i=1;i<=n;i++)
		{
			cin>>dp[i][i];
			dp[i][i-1] = 1;
			root[i][i] = i;
		}
		for(int len = 1;len<n;len++)
		{
			for(int i=1;i+len<=n;i++)
			{
				int j = i+len;
				dp[i][j] = dp[i+1][j]+dp[i][i];
				root[i][j] = i;
				for(int k=i+1;k<j;k++)
				{
					if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+dp[k][k])
					{
						dp[i][j]=dp[i][k-1]*dp[k+1][j]+dp[k][k];
						root[i][j] = k;
					}
				}
			}
		}
		cout<<dp[1][n]<<endl;
		print(1,n);
	}
	return 0;
}

PS:等等,这是个树形dp?

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/83118134