CF1312E Array Shrinking 题解 区间DP+DAG上的DP

题目链接:https://www.luogu.com.cn/problem/CF1312E

解题思路:

本题要做两次DP。

第一次DP:区间DP。

定义 \(f[i][j]\) 表示 \([i,j]\) 范围内的数合并成一个数之后的这个数是啥;如果没有办法合并成一个数,则 \(f[i][j] = -1\)

第二次DP:DAG上的DP。

如果 \(f[i][j] \ne -1\),则从 \(i-1\)\(j\) 连一条长度为 \(1\) 的边,求点 \(0\) 到点 \(n\) 的最短路,因为是DAG,所以直接DP求解(\(dp[i]\) 表示的就是 \(0 \rightarrow i\) 的最短路长度)。

示例代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
int n, a[maxn], f[maxn][maxn], dp[maxn];
bool vis[maxn][maxn];
int dfs(int L, int R) {
    if (vis[L][R]) return f[L][R];
    vis[L][R] = true;
    f[L][R] = -1;
    if (L == R) return f[L][R] = a[L];
    for (int i = L; i < R; i ++) {
        int tmp1 = dfs(L, i);
        int tmp2 = dfs(i+1, R);
        if (tmp1 != -1 && tmp1 == tmp2) {
            if (f[L][R] == -1 || f[L][R] > tmp1+1) {
                f[L][R] = tmp1 + 1;
            }
        }
    }
    return f[L][R];
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) scanf("%d", a+i);
    memset(dp, 0x3f, sizeof(dp));
    dp[0] = 0;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= i; j ++)
            if (dfs(j, i) != -1)
                dp[i] = min(dp[i], dp[j-1]+1);
    printf("%d\n", dp[n]);
    return 0;
}
posted @ 2020-09-30 16:04  quanjun  阅读(157)  评论(0编辑  收藏  举报