ACM(线性动态规划(线性DP))

线性规划(线性DP)

线性动态规划
明确问题关键
1.重叠子问题 2.状态转移方程(最关键) 3.最优子结构
解题基本套路
1.明确状态
2.明确选择
3.明确dp函数和数组的定义
4.明确base case(最开始的设置)
核心:穷举(但是是高级穷举,意为怎么简单怎么来,尽量减少代码运行时间,精简代码)
代码框架
初始化 base case(可最后考虑)
dp[0][0][…]=base;
进行状态转移
for(状态1以及状态1里的所有值)
for(状态2以及状态2里的所有值)
for…
寻找最值
dp[状态1][状态2][…]=求最值;

经典例题

1.寻找最长上升子序列

输入 1 5 3 4 6 放入数组a[]
输出 4
1.设状态量dp[i] (表示以i结尾的最长上升子序列)
2.明确选择 及dp[i]只能由1—i-1转移过来
且要接进来的序列一定是小于数组a[i]
3.明确dp[]函数
dp[i]=max( dp[i], dp[1—i-1]+1)
4.最后明确base case
dp[0]=1;
dp[i]=1;及每一个值的最短上升子序列为它本身
5.找寻最值
实现代码

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{   long long n;
   while(cin>>n)
   {if(n==0)
{break;}
long long a[10000],f[10000]={0};
    for(int q=0;q<n;q++)
    {cin>>a[q];}
    f[0]=1;
    for(int q=1;q<n;q++)
    {f[q]=1;
    for(int w=0;w<q;w++)
    if(a[q]>a[w])
    {f[q]=max(f[q],f[w]+1);
    }}
    sort(f,f+n);
    cout<<f[n-1]<<endl;
}
    return 0;
}

本周我在Vritual Judge上遇见了一个与此题类型相同的题,题意为寻找最大上升子序列,与此题解法一致。唯一要做区分的是最长不一定是最大。
只需将第三四步改一下即可
3.明确dp[]函数
dp[i]=max( dp[i], dp[1—i-1]+a[i])
4.最后明确base case
dp[0]=a[0];
dp[i]=a[i];及每一个值的最短上升子序列的最大值为它本身

2.寻找最长公共子字符串

输入 abcfbc abfcab
输出 4
1.设状态量 dp[i] [q] (表示A串以i结尾,B串以q结尾的最长公共子字符串)
2.明确选择
if ( a[i]= b[q])
dp[i][q]只能由dp[ i-1][ q-1]转化而来
else
dp[i][q]= max(dp[ i-1][ q],dp[ i][ q-1])
3.明确dp[]函数
if(a[i]==b[q])
{ dp[i][q]=dp[i-1][q-1]+1;}
else
{dp[i][q]=max(dp[i-1][q],f[i][q-1]);}
4.明确base case
dp[0][0]=0
令A B两字符串改为从1-n+1(前面空出一个元素)
代码实现

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
string a,b;
int main()
{   while(cin>>a,cin>>b)
    {int f[1000][1000];
    f[0][0]=0;
    for(int q=a.size();q>0;q--)
    {a[q]=a[q-1];}
    for(int w=b.size();w>0;w--)
    {b[w]=b[w-1];}
    for(int q=1;q<=a.size();q++)
    {for(int w=1;w<=b.size();w++)
    {if(a[q]==b[w])
    {
    f[q][w]=f[q-1][w-1]+1;}
    else
    {f[q][w]=max(f[q-1][w],f[q][w-1]);}}
    }
    int d=a.length();
    int g=b.length();
    cout<<f[d][g]<<endl;
    }
    return 0;
}

3.整数的划分

题意为将整数n划分为不同个整数的和,有多少种划分方法。
输入 6
输出 4
1.设状态量dp[i] [j] (表示整数i被划分为j个数有多少种划分方式)
2.明确选择
及dp[i][j]只能由dp[i-j][j]以及dp[i-j][j-1]转化过来
dp[i-j][j]转化为dp[i][j]时只需将其每个元素都加一
dp[i-j][j-1]转化为dp[i][j]时只需将数组再加上个1元素
3.明确dp[]函数
dp[i][j]=dp[i-j][j]+dp[i-j][j-1];
4.最后明确base case
dp[0][0]=0;
本周关于dp问题较为多,只列举了几个较为经典的例题,只希望从中总结解题的套路与方法,最起码先把dp的解题思路熟悉一下

本周笔记
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值