算法提高课第一章区间dp

区间可以划分为左右两边,而且左右两边的答案互不影响,可以进行区间dp。常用方法:迭代式、记忆化搜索

环形区间dp

环形石子dp

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 410;
const int inf = 0x3f3f3f3f;
int n;
int s[N], w[N];
int f[N][N], g[N][N];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ )
    {
        cin >> w[i];
        w[i + n] = w[i];
    }
    memset(f, 0x3f, sizeof f);
    memset(g, -0x3f, sizeof g);
    for(int i = 1; i <= n * 2; i ++ ) s[i] = s[i - 1] + w[i];
    
    for(int len = 1; len <= n; len ++ )
    for(int l = 1; l + len - 1 <= n * 2; l ++ )
    {
        int r = l + len - 1;
        if(len == 1) f[l][r] = g[l][r] = 0;
        else
        {
            for(int k = l; k < r; k ++ )
            {
                f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
                g[l][r] = max(g[l][r], g[l][k] + g[k + 1][r] + s[r] - s[l - 1]);
            }
        }
    }
    int ans1 = inf, ans2 = -inf;
    for(int i = 1; i <= n; i ++ )
    {
        ans1 = min(ans1, f[i][i + n - 1]);
        ans2 = max(ans2, g[i][i + n - 1]);
    }
    cout << ans1 << endl << ans2 << endl;
}

能量项链

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 210;
int f[N][N];
int w[N];
int n;
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) 
    {
        cin >> w[i];
        w[i + n] = w[i];
    }
    for(int len = 3; len <= n + 1; len ++ )
    for(int l = 1; l + len - 1 <= 2 * n; l ++ )
    {
        int r = l + len - 1;
        for(int k = l + 1; k < r; k ++ )
        {
            f[l][r] = max(f[l][r], f[l][k] + f[k][r] + w[l] * w[k] * w[r]);
        }
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++ ) ans = max(ans, f[i][i + n]);
    cout << ans;
}

区间dp记录方案数

加分二叉树

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 33;
int g[N][N];
int n;
int w[N];
int f[N][N];
void dfs(int l, int r)
{
    if(l > r) return;
    int root = g[l][r];
    cout << root << " ";
    dfs(l, root - 1);
    dfs(root + 1, r);
}
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> w[i];

    for(int len = 1; len <= n; len ++ )
    for(int l = 1; l + len - 1 <= n; l ++ )
    {
        int r = l + len - 1;
        if(len == 1) 
        {
            f[l][r] = w[l];
            g[l][r] = l;
            continue;
        }
        for(int k = l; k <= r; k ++ )
        {
            int left = k == l ? 1 : f[l][k - 1];
            int right = k == r ? 1 : f[k + 1][r];
            int get = left * right + w[k];
            if(f[l][r] < get)
            {
                f[l][r] = get;
                g[l][r] = k;
            }
        }
    }
    cout << f[1][n] << endl;
    dfs(1, n);
}

区间dp和高精度

凸多边形划分

#include<bits/stdc++.h>
using namespace std;
const int N =  55;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
__int128 f[N][N];
__int128 w[N];
const __int128 inf = 1e27;
int main(){
    int n;
    cin >>n;
    for(int i =1 ; i <= n ; i++) w[i] = read();
    for(int len = 3; len <= n; len++){
        for(int l = 1; l +len - 1 <= n; l++){
            int r = l + len -1;
            f[l][r] = inf;
            for(int k = l+ 1; k < r; k++){
                f[l][r] = min(f[l][r], f[l][k] + f[k][r] + w[l]*w[k]*w[r]);
            }
        }
    }
    print(f[1][n]);
    return 0;
}

二维区间dp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值