线性dp原理

简介: 笔记

线性DP


数字三角形

给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

        7
      3   8
    8   1   0
  2   7   4   4
4   5   2   6   5


状态表示

f[i][j] : 所有从起点走到(i,j)的路径最大值


状态计算

f[i][j] = Max(f[i-1][j-1],f[i-1][j]) + a[i][j]


最长上升子序列(LIS)

给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。


朴素算法

状态表示

f[i]:所有以第i个数结尾的上升子序列


状态计算

10.png

const int N = 1010;
int f[N][N];
char a[N],b[N];
int main() {
  int n,m;cin >> n >> m;
  scanf("%s%s",a+1,b+1);
  for(int i = 1;i <= n;++i){
      for(int j = 1; j<=m;++j){
          if(a[i] == b[j])f[i][j] = f[i -1][j - 1] + 1;
          else{
              f[i][j] = max(f[i-1][j],f[i][j-1]);
          }
      }
  }
  cout << f[n][m];
  return 0;
}


最短编辑距离

给定两个字符串A和B,现在要将A经过若干操作变为B,可进行的操作有:


删除–将字符串A中的某个字符删除。

插入–在字符串A的某个位置插入某个字符。

替换–将字符串A中的某个字符替换为另一个字符。

现在请你求出,将A变为B至少需要进行多少次操作。


状态表示

f[i][j]:所有将a[1~i]变成b[1~j]的操作方式


状态计算

11.png

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define eps 1e-6
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) { return x & -x; }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 1010;
char a[N], b[N];
int n, m;
int f[N][N];
int main() {
  scanf("%d%s", &n, a + 1);
  scanf("%d%s", &m, b + 1);
  for (int i = 0;i <= n;++i)f[i][0] = i;
  for (int i = 0;i <= m;++i)f[0][i] = i;
  for (int i = 1; i <= n;++i) {
    for (int j = 1;j <= m;++j) {
      f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
      if(a[i] == b[j])f[i][j] = min(f[i][j],f[i-1][j-1]);
      else f[i][j] = min(f[i][j],f[i-1][j-1] + 1);
    }
  }
  cout << f[n][m];
  return 0;
}


编辑距离

给定n个长度不超过10的字符串以及m次询问,每次询问给出一个字符串和一个操作次数上限。


对于每次询问,请你求出给定的n个字符串中有多少个字符串可以在上限操作次数内经过操作变成询问给出的字符串。


每个对字符串进行的单个字符的插入、删除或替换算作一次操作。


进行多次最短编辑距离比较即可

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define eps 1e-6
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) { return x & -x; }
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 15, M = 1010;
char s[M][N];
int f[N][N];
int n, m;
int edit_distance(char a[], char b[]) {
  int la = strlen(a + 1);
  int lb = strlen(b + 1);
  for (int i = 0;i <= la;++i)f[i][0] = i;
  for (int i = 0;i <= lb;++i)f[0][i] = i;
  for (int i = 1;i <= la;++i) {
    for (int j = 1;j <= lb;++j) {
      f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
      f[i][j] = min(f[i][j], f[i - 1][j - 1] + (a[i] != b[j]));
    }
  }
  return f[la][lb];
}
int main() {
  cin >> n >> m;
  for (int i = 0;i < n;++i)scanf("%s", s[i] + 1);
  while (m--) {
    int limit;
    char str[N];
    scanf("%s%d", str + 1, &limit);
    int res = 0;
    for (int i = 0;i < n;++i) {
      if (edit_distance(str, s[i]) <= limit)
        ++res;
    }
    cout << res << endl;
  }
  return 0;
}


目录
相关文章
|
存储 人工智能 算法
【算法分析与设计】动态规划(下)(一)
【算法分析与设计】动态规划(下)
|
1月前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
101 0
|
1月前
|
人工智能 算法 BI
【算法】 线性DP(C/C++)
【算法】 线性DP(C/C++)
|
5月前
|
人工智能 C#
一文搞懂:【62测试】【状压dp】【dfs序】【线段树】
一文搞懂:【62测试】【状压dp】【dfs序】【线段树】
24 0
|
6月前
|
测试技术
【一刷《剑指Offer》】面试题 9:斐波那契数列(扩展:青蛙跳台阶、矩阵覆盖)
【一刷《剑指Offer》】面试题 9:斐波那契数列(扩展:青蛙跳台阶、矩阵覆盖)
|
存储 算法
【算法分析与设计】动态规划(下)(三)
【算法分析与设计】动态规划(下)
|
消息中间件 人工智能 算法
【算法分析与设计】动态规划(下)(二)
【算法分析与设计】动态规划(下)
|
算法
贪心算法的思路和典型例题
贪心算法的思路和典型例题
|
算法 C++
|
人工智能 算法 Java
线性DP算法的实现
线性DP算法的实现
线性DP算法的实现