动态规划_线性动态规划,区间动态规划

Posted 一只特立独行的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划_线性动态规划,区间动态规划相关的知识,希望对你有一定的参考价值。

模板题链接:

数字三角形
最长递增子序列
最长公共子序列
石子合并

线性规划

数字三角形

思路:

状态表示: a r r [ i ] [ j ] arr[i][j] arr[i][j]表示从(1,1)出发到(i,j)的最长路径。
状态表示: a r r [ i ] [ j ] = m a x ( a r r [ i − 1 ] [ j − 1 ] , a r r [ i − 1 ] [ j ] ) + a r r [ i ] [ j ] arr[i][j]=max(arr[i-1][j-1],arr[i-1][j])+arr[i][j] arr[i][j]=max(arr[i1][j1],arr[i1][j])+arr[i][j]

代码:

#include<iostream>

using namespace std;

const int N = 505,INF=1e9;

int arr[N][N];

int main(){
    int n;
    cin>>n;
    for(int i=0;i<=n;i++){//初始化
        for(int j=0;j<=n;j++){
            arr[i][j]=-INF;
        }
    }
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            cin>>arr[i][j];
        }
    }
    for(int i=2;i<=n;i++){//状态转移
        for(int j=1;j<=i;j++){
            arr[i][j]+=max(arr[i-1][j-1],arr[i-1][j]);
        }
    }
    int res=-INF;
    for(int i=1;i<=n;i++) res=max(res,arr[n][i]);
    cout<<res<<endl;
    return 0;
}

最长上升子序列:

思路:

状态表示: f [ i ] f[i] f[i]表示以i号数字结尾的最长公共自序列长度。
状态表示: f [ i ] = m a x { f [ j ] + 1 ∣ j ∈ { j ∣ a [ j ] < a [ i ] } } f[i]=max\\{f[j]+1|j∈\\{j|a[j]<a[i]\\}\\} f[i]=max{f[j]+1j{ja[j]<a[i]}}

代码:

#include<iostream>

using namespace std;

const int N = 1005;

int a[N],f[N];

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        f[i]=1;
        for(int j=1;j<i;j++){
            if(a[j]<a[i]){
               f[i]=max(f[i],f[j]+1); //状态转移
            }
        }
    }
    int res=0;
    for(int i=1;i<=n;i++){
        res=max(res,f[i]);
    }
    cout<<res<<endl;
    return 0;
}

最长公共子序列

思路:

状态表示: f [ i ] [ j ] f[i][j] f[i][j]表示a字符串的前i个字符和b字符串的前j个字符的最长公共自序列。
状态表示: f [ i ] [ j ] = m a x { f [ i − 1 ] [ j − 1 ] , f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] , f [ i − 1 ] [ j − 1 ] + 1 } f[i][j]=max\\{f[i-1][j-1],f[i-1][j],f[i][j-1],f[i-1][j-1]+1\\} f[i][j]=max{f[i1][j1],f[i1][j],f[i][j1],f[i1][j1]+1}
分别表示不包括i和j位字符,选包括j位字符,包括i位字符,包括i位和j位字符。

代码:

#include<iostream>

using namespace std;

const int N = 1e3+5;

int n,m,f[N][N];
char a[N],b[N];

int main(){
    int res=0;
    scanf("%d%d",&n,&m);
    scanf("%s%s",a+1,b+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            f[i][j]=max(f[i][j-1],f[i-1][j]);
            if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1); 
        }
    }
    cout<<f[n][m]<<endl;
    return 0;
}

区间动态规划

石子合并

思路:

状态表示: f [ l ] [ r ] f[l][r] f[l][r]表示合并从i到j区间的石子的最小代价。
状态表示: f [ l ] [ r ] = m i n { f [ l ] [ k ] + f [ k + 1 ] [ r ] + s u m ( a [ l ] , . . . , a [ r ] ) } , k ∈ [ l , r − 1 ] f[l][r]=min\\{f[l][k]+f[k+1][r]+sum(a[l],...,a[r])\\},k∈[l,r-1] f[l][r]=min{f[l][k]+f[k+1][r]+sum(a[l],...,a[r])},k[l,r1]
一般区间长度从小到大循环。

代码:

#include<iostream>
#include<cstring>

using namespace std;

const int N = 305;

int a[N],f[N][N],s[N];

int main(){
    
    int n;
    cin>>n;
    
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    
    for(int len=2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int l=i,r=i+len-1;
            f[l][r]=1e8;
            for(int j=l;j<r;j++){
                f[l][r]=min(f[l][r],f[l][j]+f[j+1][r]+s[r]-s[l-1]);
            }
        }
    }
    
    cout<<f[1][n]<<endl;
    return 0;
}

以上是关于动态规划_线性动态规划,区间动态规划的主要内容,如果未能解决你的问题,请参考以下文章

区间上的动态规划

动态规划专题选做

ACM - 动态规划小白入门:背包 / 线性 / 区间 / 计数 / 数位统计 / 状压 / 树形 / 记忆化 DP

算法动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )

算法动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )

线性动态规划尼克的任务