线性DP、区间DP

线形DP

AcWing 898. 数字三角形

将想要计算的点的状态分为两部分,从左上角、右上角两部分走过来。求最大值:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 510, INF= 1e9;
int a[N][N], f[N][N];
int n;

int main(){
	cin >> n;
	memset(f, -0x3f, sizeof f);
	
	for(int i = 1; i<=n; i++){
		for(int j = 1; j<=i; j++) cin >> a[i][j];
	}
	
	f[0][0] = 0;
	for(int i = 1; i<=n; i++){
		for(int j = 1; j<=i; j++){
			f[i][j] = max(f[i-1][j-1]+a[i][j], f[i-1][j]+a[i][j]);
		}
	}
	
	int res = -INF;
	for(int i =1 ; i<=n; i++){
//		cout << "------1" << endl;
		res = max(res, f[n][i]); 
	}
	
	cout << res;
	return 0;
} 

AcWing 895. 最长上升子序列

需要计算点是由什么状态到达的, 该点的前面状态是小于这个点的位置。可以用数组g来记录路径,f[i] = f[j] + 1; g[i] = j; 存储该节点的上一个节点坐标

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N= 1010;
int a[N], f[N], g[N];
int n;

int main(){
	cin >> n;
	for(int i = 1; i<=n; i++) cin >> a[i];
	
	for(int i = 1; i<=n; i++){
		f[i] = 1;//最小的长度为1; 
		g[i] = 0;
		for(int j = 1; j<i; j++){
			if(a[j] < a[i]){
				if(f[i] < f[j]+1){
					f[i] = f[j] + 1;
					g[i] = j;
				}

			}
		}
	}
	int res = 0;
	int k = 0;
	for(int i =1; i<=n; i++)  
	{
		res = max(res, f[i]);
		k = i;
	}

	
	cout << res << endl;
	
	for(int i = 0, len = f[k]; i<len; i++){
		cout << a[k] << " ";
		k = g[k];
	}
	return 0;
}

896. 最长上升子序列 II

用p 数组来存储结果,遍历输入的数组与p数组的结尾比较大的就进入,当a[i] <= f[cnt] 的时,我们就用a[i]去替代数组 p 中的第一个**大于等于a[i]**的数

我们用a[i]去替代f[i]的含义是:以a[i]为最后一个数的严格单调递增序列,这个序列中数的个数为l个。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
int a[N], q[N];
int n;
int cnt;
int find(int x){
	int l = 0, r= cnt;
	while(l < r){
		int mid = l + r >> 1;
		if(q[mid] >= x) r = mid;
		else l = mid + 1;
	} 
	
	return r;
}

int main(){
	cin >> n;
	for(int i = 1; i<=n; i++) cin >> a[i];
	
	memset(q, -0x3f, sizeof q);

	for(int i = 1; i<=n; i++){
		if(a[i] > q[cnt]){
			q[++cnt] = a[i];
		}else {
			q[find(a[i])] = a[i];
		}
	}
	cout << cnt;	
	return 0;
}
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1010;
int a[N], q[N];
int n;

int main(){
    cin >> n ;
    
    for(int i =1; i<=n; i++) cin >> a[i];
    
    int len = 0;
    q[0] = -2e9;
    for(int i = 1; i<=n; i++){
        int l = 0, r = len ;
        while(l < r){
            int mid = l + r + 1 >> 1;

            if(q[mid] < a[i]) l = mid;
            else r = mid-1;
        }
        
        len = max(len, l+1);
        q[l+1] = a[i];  
    }
    
    cout << len;
    return 0;
}

897. 最长公共子序列

状态转移:f [ i ][ j ] 是由当前位置的字符是否相等来判断的, 如果相等就可以直接转移到 f[i-1][j-1] +1。不相等的话,可以对**f[i-1][j] (不包含a[i]的最大值),f[i][j-1]**两种状态取max来转移。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

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

int main(){
	cin >> n >> m;
	cin >> a+1 >> b+1;
	
	for(int i = 1; i<=n; i++){
		for(int j = 1; j<=m; j++){
			f[i][j] = max(f[i-1][j], f[i][j-1]);//这种一定小于f[i-1][j-1] + 1可以先求出
			if(a[i] == b[j]) f[i][j] = max(f[i-1][j-1] + 1, f[i][j]);
		}
	}
	
	cout << f[n][m];
	return 0;
}

902. 最短编辑距离

状态方程:f[i][j]代表前 a的前i个字符和b的前j个字符相同最少要操作多少次

f[ i ][ j ] =min({

// f [ i - 1][ j ] + 1, // 删除 a[i](删之前i-1个 = j个

// f [ i ][ j-1 ] + 1, // 在 a[i] 后插入 b[j](添加之前前i个等于j-1个

// f[ i-1 ][ j-1 ] + (a[ i ] != b[ j ]) // 替换:不同就+1,相同就+0

// });

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

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

int main(){
	cin >> n >> a+1;
	cin >> m >> b+1;
//	//f[i][j] = min(f[i][j], f[i-1][j-1]);最小值不能直接先比 
//	memset(f, 0x3f, sizeof f); 
	//f[i][j]代表前 a的前i个字符和b的前j个字符最少要操作多少次 
	for(int i = 1; i<=m; i++) f[0][i] = i; //表示 a 有0个字符,b有i个需要增加i次
	for(int i = 1; i<=n; i++) f[i][0] = i;

	for(int i = 1; i<=n; i++){
		for(int j = 1; j<=m; j++){
//			f[i][j] = min({
//    			f[i-1][j] + 1,   // 删除 a[i]
//    			f[i][j-1] + 1,   // 在 a[i] 后插入 b[j]
//   				 f[i-1][j-1] + (a[i] != b[j])  // 替换:不同就+1,相同就+0
//				});
			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];
}

AcWing 899. 编辑距离

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1010;
char str[N][N];
int f[N][N];
int n, m;

int edit_distance(char a[N], char b[N]){
	int la = strlen(a+1), lb = strlen(b+1);
	
	for(int i=1; i<=lb; i++) f[0][i] = i;
	for(int i=1; i<=la; i++) f[i][0] = 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-1][j-1]+(a[i] != b[j])});
		}
	}
	return f[la][lb];
}

int main(){
	cin >> n >> m;
	for(int i = 1; i<=n; i++) cin >> str[i] + 1;
	
	while(m--){
		char s[N];
		int limit;
		cin >> s+1 >> limit;
		int res =0 ;
		
		for(int i =1 ; i<=n; i++){
			if(edit_distance(str[i], s) <=limit) res++;
		}
		cout << res << endl;
	}
	return 0;
} 

区间DP

282. 石子合并

状态转移方程中的集合的表达 :f[l][r] = 把 l ~ r 这一段石子合并成一堆的最小代价。

从小大大列举区间 (len = 2; len<=n; len++)再枚举起点(i = 1; i+len-1<=n; i++)能枚举出所有区间为二的状态;for(int k = l; k<r; k++){ **f[l][r] = min(f[l][r], f[l][k] + f[k+1][r]+s[r] - s[l-1]);**并且能比较出区间怎么配分状态最小。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 310;
int f[N][N], s[N];
int n;

int main(){
	cin >> n;
	for(int i = 1; i<=n; i++) cin >> s[i];
	
	for(int i = 1; i<=n; i++) s[i] += s[i-1];
	
//	memset(f, 0x3f, sizeof f); 
	for(int len = 2; len<=n; len++){//这个区间要一直枚举到最大 
		for(int i = 1; i+len-1<=n; i++){//枚举起点 不能 i<n;整段都有起点 
			int l = i, r = i+len-1;
			//区间分为两半,计算每个区间求最小值 
			f[l][r] = 1e9;
			for(int k = l; k<r; k++){                  //区间最小 l-1
				f[l][r] = min(f[l][r], f[l][k] + f[k+1][r]+s[r] - s[l-1]);
			}
		}
	}
	cout << f[1][n];
	return 0;
}
相关推荐
怨言.2 小时前
Java内部类详解:从基础概念到实战应用(附案例)
java·开发语言
AC赳赳老秦2 小时前
OpenClaw image-processing技能实操:批量抠图、图片尺寸调整,适配办公需求
开发语言·前端·人工智能·python·深度学习·机器学习·openclaw
XiYang-DING2 小时前
【Java】 Java 集合框架
java·开发语言
charlie1145141912 小时前
嵌入式C++教程实战之Linux下的单片机编程(9):HAL时钟使能 —— 不开时钟,外设就是一坨睡死的硅
linux·开发语言·c++·单片机·嵌入式硬件·c
放羊郎2 小时前
机器人跟随算法
算法·机器人
Tong Z2 小时前
Buffer Pool的数据结构
数据结构
liu****2 小时前
第十五届蓝桥杯大赛软件赛国赛C/C++大学B组
c++·算法·蓝桥杯·acm
zhooyu2 小时前
利用叉乘判断OpenGL中的左右关系
c++·3d·opengl
diving deep2 小时前
从零构建大模型--实操--搭建python环境
开发语言·python