【区间dp】分离与合体

原题链接:https://loj.ac/problem/10151

题目描述

此处省略原题描述,又长又臭

输入

第一行一个正整数n(2≤n≤300)第二行为n个用空格分开的正整数,表示1~n区域里每把金钥匙的价值。保证运算过程及结果不超出int范围

输出

第一行的一个数,即获得的最大价值。第二行按照分离阶段从前到后,区域从左向右的顺序,输出发生分离的区域编号,中间用一个空格隔开,若有多种方案,选择分离区域尽量靠左的方案(也可以理解为输出字典序最小的)

样例输入

7
1 2 3 4 5 6 7

样例输出

238
1 2 3 4 5 6

题目类型:区间dp+广搜

思路

按区间长度从小到大枚举所有区间 [ j , i ],再枚举所有决策点 t∈[ j , i−1 ],
dp 方程为:dp[j][t]=max(dp[j][t],(a[t]+a[j])*a[k]+ dp[j][k]+dp[k+1][t]);
然后用广搜思路求出路径:区间最优决策点在dp的时候记录一下就可以,输出可以用队列来实现,和bfs的过程类似。

完整代码

#include
using namespace std;
#define ll long long
const int N=100010;
int ans,a[1000],dp[1000][1000],n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j+i-1<=n;j++)
        {
            int t=i+j-1;
            for(int k=j;k<t;k++)
            {
                dp[j][t]=max(dp[j][t],(a[t]+a[j])*a[k]+dp[j][k]+dp[k+1][t]);
            }
        }
    }
    cout<<dp[1][n]<<endl;
    queue<int>q1,q2;
    q1.push(1);
    q2.push(n);
    while(q1.size())
    {
        int i=q1.front(),j=q2.front();
        q1.pop(),q2.pop();
        for(int k=i;k<j;k++)
        {
            if(dp[i][j]==(a[i]+a[j])*a[k]+dp[i][k]+dp[k+1][j])
            {
                printf("%d ",k);
                q1.push(i),q2.push(k);
                q1.push(k+1),q2.push(j);
                break;
            }
        }
    }
    return 0;
}

你可能感兴趣的:(区间dp)