照例送上题目链接: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?