动态规划【7】之区间动态规划

区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来由很大的关系。令状态 f [ i , j ] f[i,j] 表示将下标位置 i i j j 的所有元素合并能获得的价值的最大值,那么 f [ i , j ] = max { f [ i , k ] + f [ k + 1 , j ] + c o s t } f[i,j]=\max\{f[i,k]+f[k+1,j]+cost\} ,其中 c o s t cost 为将这两组元素合并起来的代价1, i k < j i\leq k<j

例题一 石子合并

例题:luogu1880 [NOI1995]石子合并
思路参考自:https://oi-wiki.org/dp/interval/。简单来说,三重for循环,第一重是长度 l e n len ,第二重是开始下标 i i (前两重可以确定结束下标 j j ),第三重是合并位置 k k

解决环的问题:复制一份,变成 2 n 2n 的序列。

注意点:最小值初始化 f 1 [ i ] [ i ] = 0 f1[i][i]=0 表示一个石头不需要代价,其他点 f 1 [ i ] [ j ] = I N F f1[i][j]=INF (无穷大)。

hyy提供的代码:

#include <bits/stdc++.h>
using namespace std;

int f[210][210];
int f1[210][210];
int n;
int a[210];
int sum[210];

int main(){
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++)     sum[i]=sum[i-1]+a[i];
    for(int i=1;i<=2*n;i++){
        for(int j=1;j<=2*n;j++){
            f1[i][j]=2e6;
        }
    }
    for(int i=1;i<=2*n;i++) f1[i][i]=0,f[i][i]=0;
    for(int len=2;len<=n;len++){
        for(int i=1;i<=2*n;i++){
            int j=i+len-1;
            if(j>=2*n)   break;
            for(int k=i;k<j;k++){
                f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
                f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]);
            }
        }
    }
    int ans=0,ans1=2e6;
    for(int i=1;i<=n;i++){
        ans1=min(ans1,f1[i][i+n-1]);
        ans=max(ans,f[i][i+n-1]);
    }
    cout << ans1<<endl<<ans;
    return 0;
}

例题二 能量项链

例题:luogu1063 能量项链

处理方式与例题一非常类似,唯一要修改的地方是 c o s t cost max { f [ i , k ] + f [ k + 1 ] [ j ] + c o s t } \max\{f[i,k]+f[k+1][j]+cost\} 的cost为 a [ i ] a [ k + 1 ] a [ j + 1 ] a[i]*a[k+1]*a[j+1] .

代码:

/* ***********************************************
Author        : VFVrPQ
Created Time  : 一  3/ 2 14:45:08 2020
File Name     : luogu1063能量项链.cpp
Problem       : 
Description   : 
Solution      : 
Tag           : 
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
#define DEBUG(x) cout<<x<<endl;
const int N = 2e2+10;
const int M = 1e9+7;
const int INF = 1e9+7;

int dp[N][N];
int a[N];
int n;
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[n+i] = a[i];
    }
    for (int i=1;i<=n+n;i++) dp[i][i] = 0;

    for (int len=2;len<=n;len++){
        for (int i=1;i<=n+n;i++){
            int j = i+len-1;
            if (j>=n+n) break;
            for (int k=i;k<j;k++){
                dp[i][j] = max(dp[i][j], dp[i][k]+dp[k+1][j]+a[i]*a[k+1]*a[j+1]);
            }
        }
    }
    
    int ans = 0;
    for (int i=1;i<=n;i++) ans = max(ans, dp[i][i+n-1]);
    printf("%d\n",ans);
    return 0;
}

  1. https://oi-wiki.org/dp/interval/ ↩︎

发布了74 篇原创文章 · 获赞 30 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/MustImproved/article/details/104610760