1. 程式人生 > 實用技巧 >習題:Array Shrinking(DP)

習題:Array Shrinking(DP)

題目

傳送門

思路

考慮到一個區間如果能縮成一個點,那麼這個點的值一定是確定的

所以我們設\(dp[l][r]\)為區間\(l,r\)最終縮成的點的值

如果不能縮成一個點,那麼\(dp[l][r]=0\)

\(dp[l][r]\)的轉移列舉一個分界點即可

之後就是一個劃分區間的問題

按照套路,設\(f[i]\)為前i個數構造的陣列剩餘的最小值

\(f[i]=min\{f[j]+1[dp[j+1][i]!=0]\}\)

程式碼

#include<iostream>
#include<cstring>
using namespace std;
int n;
int a[505];
int f[505][505];
/*
區間l~r縮成一個點之後的數是多少
如果不能縮成一個點,值為0
*/
int dp[505];//前i個數的最小長度
int dfs1(int l,int r)
{
    if(f[l][r]!=-1)
        return f[l][r];
    for(int i=l;i<r;i++)
    {
        if(dfs1(l,i)==dfs1(i+1,r)&&dfs1(l,i)!=0)
        {
            f[l][r]=f[l][i]+1;
            return f[l][r];
        }
    }
    f[l][r]=0;
    return 0;
}
int main()
{
	ios::sync_with_stdio(false);
	memset(f,-1,sizeof(f));
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];       
        f[i][i]=a[i];
    }
    dfs1(1,n);
    for(int i=1;i<=n;i++)
    {
        dp[i]=i;
        for(int j=0;j<i;j++)
            if(f[j+1][i]!=0)
                dp[i]=min(dp[i],dp[j]+1);
    }
    cout<<dp[n];
    return 0;
}