首页 > 其他分享 >「Day 9 & 10—DP问题」

「Day 9 & 10—DP问题」

时间:2024-08-14 23:05:32浏览次数:9  
标签:10 int max 代码 DP ans include Day dp

DP问题

定义

什么是 \(DP\),答曰:一种通过将全局问题分解成不同的子问题来进行对复杂问题的计算。
在我看来就是一种递推的 \(ProMax\) 版,依旧是用之前计算过的来推出现在要计算的。

DP板子问题

P1115 最大子段和

思路

我们用 \(dp\) 数组来定义到 \(i\) 为止,最大的子段和,那么我们在面对 \(dp_i\) 的时候,应该怎么操作呢。首先什么情况下我们要继续接着前面的选,就是前面的大于 \(0\) 的时候,否则我们就可以单开一次,让 \(dp_i = a_i\) 即可。

代码
点击查看代码
#include<iostream>
using namespace std;

const int MAXN = 2 * 1e6 + 5;
int a[MAXN];
int dp[MAXN];
int n,ans = -10086;

int main(){
	
	cin >> n;
	for(int i = 1;i <= n;i ++) cin >> a[i];
	for(int i = 1;i <= n;i ++){
		if(dp[i - 1] >= 0) dp[i] = dp[i - 1] + a[i];
		else{
			dp[i] = a[i];
		}
		ans = max(dp[i],ans);
	}
	cout << ans << "\n";
	return 0;
}

最大子矩阵问题

思路

首先呢这个题没有找到有这个题的 \(OJ\),所以就直接写了。
最大子矩阵这个问题太大了,如果是枚举的话 \(O(n^4)\) 肯定爆炸,有没有什么稍稍优化一点的方法吗?有。想一想我们刚刚说的最大子段和,如果能将这个二维问题压成一维就好了,那么如何去做呢。可以用一个线性前缀和,\(sum_i,{_j}\) 表示第 \(j\) 列前 \(i\) 个元素的前缀和。

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
	    //j表示第j列,剩下的那一维和正常的前缀和没什么大区别。
        pre[i][j] = pre[i - 1][j] + a[i][j];
    }
}

接下来如何求呢,我们既然知道了在第 \(j\) 列上的前缀和了,那么例如
3 3
1 -2 3
-4 5 -6
7 -8 9
对于每一列的前缀和为
1 -2 3
-3 3 -3
4 -5 6
例如我们要算上界为 \(2\) 和下界为 \(3\) 的子矩阵和,也就是最后两行,其每列的和为
3 -3 3
这个该如何算呢?
利用 \(pre[3][1] - pre[2 - 1][1]\) 计算出第一列的,扩展到正常的就是: \(pre[j][k] - pre[i - 1][k]\) 其计算的就是第 \(K\) 行从第 \(i\) 到第 \(j\) 的数的和。
计算后再用最大子段和进行计算即可。

// 求解最大子矩阵和
long long ans = -inf;
for (int i = 1; i <= n; i++) { // 枚举上边界
    for (int j = i; j <= n; j++) { // 枚举下边界
        long long sum = 0;
        // 第 k 列,[i,j] 的和为:pre[j][k] - pre[i - 1][k]
        // 所以就转换为最大子段和问题了
        for (int k = 1; k <= m; k++) {
            long long tmp = pre[j][k] - pre[i - 1][k];
            if (sum >= 0) {
                sum += tmp;
            } else {
                sum = tmp;
            }
            ans = max(ans, sum);
        }
    }
}

B3637 最长上升子序列

思路+代码
#include<iostream>
using namespace std;

int n;
int a[10005],dp[10005];

int main(){
	
	cin >> n;
	for(int i = 1;i <= n;i ++){
		cin >> a[i];
	}
	for(int i = 1;i <= n;i ++){
		dp[i] = 1;
		for(int j = 1;j < i;j ++){
			//保证上升
			//如果是最长不下降子序列就把<改为<=即可
			if(a[j] < a[i]){
				//取最大的
				dp[i] = max(dp[i],dp[j] + 1);
			}
		}
	}
	int ans = -1;
	for(int i = 1;i <= n;i ++){
		ans = max(ans,dp[i]);
	}
	cout << ans << "\n";
	return 0;
}

P1439 【模板】最长公共子序列

思路

首先是我们考虑状态,\(dp[i][j]\) 表示前 \(s[i]\) 和前 \(t[i]\) 个字符的最长公共子序列长度,对于一个 \(dp[i][j]\) 来说,我们有两种情况,一是 \(s[i] == t[i]\) 这个时候让 \(dp[i][j] = dp[i - 1][j - 1] + 1\) 即可,否则就取 \(s[i]\) 结尾和 \(t[i]\) 结尾的最大值即可。

代码(无优化50pts)
点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;

int n;
int a[200005],b[200005];
int dp[8005][8005];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		cin>>b[i];
	} 
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			//两种情况
			if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1] + 1;
			else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
		}
	}
	
	cout<<dp[n][n]<<endl;
	return 0;
}

简单背包问题

P1048 [NOIP2005 普及组] 采药

思路

这个题可以说是最正规的 \(01\) 背包了,我们设一个状态 \(dp[i][j]\) 来表示在面对第 \(i\) 个物品时背包容积还剩 \(j\) 时的最大价值。
对于第 \(i\) 个物品有选和不选两种情况:
\(dp[i][j] = dp[i - 1][j]\) (不选的情况)
\(dp[i][j] = max(dp[i - 1][j - w[i]] + v[i],dp[i - 1][j])\) (选的情况)

代码
点击查看代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int dp[21][1010];
int w[21], c[21];
int main() {
    int N, V;
    cin >> N >> V;
    for (int i = 1; i <= N; i++) {
        cin >> w[i] >> c[i];
    }
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j <= V; j++) {
            if (j >= c[i]) {
                dp[i][j]=max(dp[i-1][j-c[i]]+w[i],dp[i-1][j]);
            } else {
                dp[i][j]=dp[i-1][j];
            }
        }
    }
    cout << dp[N][V] << endl;
    return 0;
}

P1757 通天之分组背包

思路

这个题和上个题唯一不同是这个题每个物品有好多件,于是我们就可以在转移的过程中枚举件数 \(k\),有如下转移方程
\(dp[i][j] = dp[i - 1][j - w[i] * k] + c[i] * k,dp[i - 1][j](j >= w[i] * k)\)

代码
点击查看代码
for (int i = 1; i <= N; i++) {
    for (int j = 0; j <= V; j++) {
        for (int k = 0; k <= n[i]; k++) {
            if (j >= c[i] * k) {
                dp[i][j] = max(dp[i - 1][j - c[i] * k] + w[i] * k, dp[i][j]);
            }
        }
    }
}

P1616 疯狂的采药

思路

这个题和上一个的唯一区别是这个题我物品你可以随便取,那么又该如何去做呢?
朴素的方法是这样:

for (int i = 1; i <= N; i++) {
    for (int j = 0; j <= V; j++) {
        for (int k = 0; k * c[i] <= j; k++) {
            dp[i][j] = max(dp[i - 1][j - c[i] * k] + w[i] * k, dp[i][j]);
        }
    }
}

但是啊这破玩意时间复杂度太高了啊,那就优化,如何优化嘞?我们发现

\(dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + c[i],dp[i - 1][j - w[i] * 2] - c[i] * 2,...)\)
然鹅

\(dp[i][j - c[i]] = max(dp[i - 1][j - w[i]] + c[i],dp[i - 1][j - w[i] * 2] + c[i] * 2,dp[i - 1][j - w[i] * 3] + c[i] * 3,...)\)
所以

\(dp[i][j] = max(dp[i - 1][j],dp[i][j - w[i]] + c[i])\)

代码
for (int i = 1; i <= n; i++) {
    for (int j = 0; j <= v; j++) {
        if (j >= c[i]) {
            dp[i][j] = max(dp[i][j - c[i]] + w[i], dp[i - 1][j]);
        } else {
            dp[i][j] = dp[i - 1][j];
        }
    }
}

简单DP问题

未完待续

标签:10,int,max,代码,DP,ans,include,Day,dp
From: https://www.cnblogs.com/To-Carpe-Diem/p/18359882

相关文章

  • day02(Linux)Shell脚本
    Shell脚本一.shell脚本基础概念1.1概念shell使用方式:手动在命令行下命令和用shell脚本shell脚本本质:shell命令的有序集合,扩展名可以为sh见名知意,也可以没有。shell既是应用程序,又是一种脚本语言(应用程序解析脚本语言)。解释型语句:不需要编译,解释一条执行一条,pytho......
  • Mybatis学习日记-day4-ResultMap
    一、学习目标    在之前的学习博客里对数据进行增删改查的操作,都是基于数据库表的列名Java对象的属性名一致的情况下,但是,这个世界并不是这么美好。        当数据库表的列名与Java对象的属性名不一致,或者数据类型需要特殊处理;此外,如果数据库中的某个列是枚......
  • MySQL-2:数据库基础知识(50%-100%)
    目录前言一、SQL语言基础1.SQL语言简介2.SQL分类3.SELECT语句的使用4.INSERT语句的使用5.UPDATE语句的使用6.DELETE语句的使用二、基本查询1.WHERE子句的使用2.ORDERBY子句的使用3.GROUPBY和HAVING子句使用4.LIMIT子句的使用总结前言前一半MySQL-1:数据库......
  • 代码随想录Day15
    110.平衡二叉树(优先掌握递归)给定一个二叉树,判断它是否是平衡二叉树平衡二叉树是指该树所有节点的左右子树的深度相差不超过1。示例1:输入:root=[3,9,20,null,null,15,7]输出:true示例2:输入:root=[1,2,2,3,3,null,null,4,4]输出:false示例3:输入:root=[]输出:t......
  • 自媒体IP-起号实战班:教你如何靠打造设计个人IP,年赚到100万!
    摘要:本文旨在探讨个人品牌在自媒体平台上的构建与运营策略,以实现持续增长的个人价值和专业影响力。关键词:个人品牌,自媒体,内容运营,客户获取,转化率1.个人品牌构建的全流程方法论本节将介绍一套系统化的个人品牌构建流程,旨在帮助设计师通过自媒体平台实现个人价值的最大化......
  • Coin Troubles题解(dp,拓扑序)
    CoinTroubles题解(dp,拓扑序)题目链接:https://codeforces.com/problemset/problem/283/C题意:有\(n\)种硬币,每种硬币都有一个价格\(ai\),现在有\(q\)个限制,每个限制会告诉你\((b,c)\),并要求\(b\)种硬币的数量严格大于\(c\)种硬币的数量。现在问你一共有多少种买硬币的方法,使得最后......
  • 自媒体IP-起号实战班:教你如何靠打造设计个人IP,年赚到100万!
    标题:个性化IP战略在设计领域的应用与实践**摘要:**本文旨在探讨在设计行业中如何通过构建个性化IP(IntellectualProperty)来增强设计师的市场竞争力和商业价值。通过一系列实操策略与方法的介绍,本文为设计师提供了一套系统化的个人品牌构建流程。**关键词:**个性化IP,设计行业......
  • 蒙特卡洛1000个风光场景并通过削减法|聚类法得到几个典型场景(matlab&python实现)
        目录1 对风光的认识2 风电DG出力概率模型 2.1 风速分布特性2.2 风电DG有功出力3 光伏DG出力概率模型 3.1 光照强度分布特性3.2光伏DG有功出力 4Python代码实现4.1数据4.2Python代码 4.3结果  5Matlab实现5.1数据5.2Matlab代码 5.......
  • 学费管理系统的设计与实现(10766)
     有需要的同学,源代码和配套文档领取,加文章最下方的名片哦一、项目演示项目演示视频二、资料介绍完整源代码(前后端源代码+SQL脚本)配套文档(LW+PPT+开题报告)远程调试控屏包运行三、技术介绍Java语言SSM框架SpringBoot框架Vue框架JSP页面Mysql数据库IDEA/Eclipse开发四、项......
  • Android10.0 最近任务Recents功能分析
    在Android10.0上,Recents功能分布在SystemUI和Launcher3里面集成.一.初始化跟Android8.1类似,先看初始化入口:1.Recents.javaRecents继承SystemUI,进程启动后会在Dependency里面通过@Inject进行初始化,然后在SystemUIService里面调用SystemUIApplication的startServicesIfNee......