Peter算法小课堂—动态规划

news2025/1/20 17:05:18

Peter来啦,好久没有更新了呢

今天,我们来讨论讨论提高组的动态规划。

动态规划

动态规划有好多经典的题,有什么背包问题、正整数拆分、杨辉三角……但是,如果考到陌生的题,怎么办呢?比如说2000年提高组的乘积最大、石子合并……,所以说,我们要理解动态规划的本质。

那么,我们动态规划的第一步就是状态定义

dp的第二步就是填表格、写状态转移方程。

最后一步就是根据状态转移方程写代码了。其实,我觉得,dp最难的地方就是第二步,其次就是根据递推式写代码。给大家练一练根据递推式写代码吧。

递推1

那么,代码很简单,长这样👇

#include<bits/stdc++.h>
using namespace std;
int f[110][1010],n,v,c[110],w[110];
int main()
{
    scanf("%d%d",&v,&n);
    for (int i=1;i<=n;++i)
        scanf("%d%d",&c[i],&w[i]);
    for (int i=1;i<=n;++i) {
        for (int j=1;j<c[i];++j)
            f[i][j]=f[i-1][j];
        for (int j=c[i];j<=v;++j)
            f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+w[i]);
    }
    printf("%d\n",f[n][v]);
    return 0;
}

再来一道题

递推2

代码长这样

#include<bits/stdc++.h>
using namespace std;
int f[1010],n,c[1010];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        scanf("%d",&c[i]);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=i;++j)
            f[i]=max(f[i],f[i-j]+c[j]);
    int k,x;
    scanf("%d",&k);
    for (int i=1;i<=k;++i) {
        scanf("%d",&x);
        printf("%d\n",f[x]);
    }
    return 0;
}

递推练完了,就要练习状态转移方程了(靠自觉)

摆花

原题链接:P1077 [NOIP2012 普及组] 摆花 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

那么这道题,我们把题意抽象化成:有 n 个数(c1​,c2​,...,cn​),0⩽ci​⩽ai​,求有多少种方案数使\sum_{i=1}^{n}c_{i}=m

首先,看到这道题,我给出5种办法,分别对应初学者、普及Oler、不大聪明的提高Oler、灰常聪明的提高Oler。

初学者

最最最简单的办法就是搜索+记忆化

#include<bits/stdc++.h>
using namespace std;
const int maxn=105, mod = 1000007;
int n, m, a[maxn], rmb[maxn][maxn];
int dfs(int x,int k)
{
    if(k > m) return 0;
    if(k == m) return 1;
    if(x == n+1) return 0;
    if(rmb[x][k]) return rmb[x][k]; //搜过了就返回
    int ans = 0;
    for(int i=0; i<=a[x]; i++) ans = (ans + dfs(x+1, k+i))%mod;
    rmb[x][k] = ans; //记录当前状态的结果
    return ans;
}
int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++) cin>>a[i];
    cout<<dfs(1,0)<<endl;
    return 0;
}

搜索所有可能的c_{i}并且记忆化。

普及Oler

其次,应该会想到动态规划了。

时间复杂度大大降低,给出代码

#include <bits/stdc++.h>
using namespace std;
const int N=109;
const int MOD=1e6+7;
int f[N][N],a[N],n,m;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	f[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			if(j-1<a[i])
				f[i][j]=(f[i-1][j]%MOD+f[i][j-1]%MOD)%MOD;
			else f[i][j]=(f[i-1][j]%MOD+f[i][j-1]%MOD-f[i-1][j-1-a[i]]%MOD+MOD)%MOD;
		}
	}
	cout<<f[n][m]<<endl;
	return 0;
}

还是比较蒟蒻的

不大聪明的提高Oler

再其次,就是前缀和优化,大家都学过,给出代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105, mod = 1000007;
int n, m, f[maxn], sum[maxn], a[maxn];
int main(){
    cin>>n>>m;
    for(int i=1; i<=n; i++) cin>>a[i];
	f[0] = 1;
    for(int i=0; i<=m; i++) sum[i] = 1;
    for(int i=1; i<=n; i++){
    	for(int j=m; j>=1; j--){
    		int t = j - min(a[i], j) - 1;
    		if(t < 0) f[j] = (f[j] + sum[j-1])%mod;
    		else f[j] = (f[j] + sum[j-1] - sum[t] + mod)%mod;
		}
		for(int j=1; j<=m; j++) sum[j] = (sum[j-1] + f[j])%mod;
	}
    cout<<f[m]<<endl;
    return 0;
}

来了,它又来了,它就是我们的生成函数!!!

灰常聪明的提高Oler

生成函数啊啊啊

大家如果不会生成函数的话,可以康康这位大佬的博客生成函数(母函数)——目前最全的讲解-CSDN博客

我们构造一个函数g(x)=\prod_{i=1}^{n}\sum_{j=0}^{a_{i}}x^{j},其中x^{m}项的系数即为答案。可以做n-1次NTT,然后输出。时间复杂度:O(n^2k\log nk)。这里我不给出代码了。

其实,也不用算出乘积,有一种更好的方法

我们约定A(x)=\sum_{i=0}^{n}a_{i}x^{i}B(x)=\sum_{i=0}^{n}b_{i}x^{i}

C(x)=A(x)B(x), 则C(x)=\sum_{i=0}^{n+m}c_{i}x^{i},其中c_{i}=\sum_{j=0}^{i}a_{j}b_{i-j},懂得都懂

这一题比较难,来一道简单亿点的题

参差不齐

n名电影演员依次排成一排,第i人的颜值为y[i],有些参差不齐。你希望挑选m个人拍一张电影海报,这m个人的前后顺序不能发生变化。你希望挑选的这排演员相邻的颜值不能相差太大,于是你定义颜值的参差不齐程度为相邻两人颜值差距的绝对值之和。求这m人的参差不齐程度最少是多少?

这一题最难的是状态定义,要是状态定义完成了的话,状态转移方程就显而易见了。

这个定义不太好,下面给出正确的定义及代码

下面给出代码👇

for(int i=1;i<=n;i++) f[i][1]=0;
for(int j=2;j<=m;j++)//枚举j代表选中人数
	for(int i=j;i<=n;i++){//枚举i代表结尾编号
		f[i][j]=INF;
		for(int k=j-1;k<i;k++)//结尾是i号时枚举k代表i号的左边邻居是几号
			f[i][j]=min(f[i][j],f[k][j-1]+abs(y[i]-y[k]));
	}
int ans=INF;
for(int i=m;i<=n;i++) ans=min(ans,f[i][m]);
cout<<ans<<endl;

乘积最大

原题链接:P1018 [NOIP2000 提高组] 乘积最大 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这题显然是一道数位dp

状态定义:f[i][j] 表示前 i 位数包含 j 个乘号所能达到的最大乘积

easy代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long f[45][60];
string in;
int n,k;//n位数  k个乘号 
long long g[45];
long long cut(int l,int r){
    long long end = 0;
    for(int i = l;i <= r;i++)
        end = end * 10 + g[i];
    return end;
}
int main(){
    cin >> n >> k >> in;
    for(int i = 1;i <= n;i++)
        g[i] = in[i - 1] - '0';
    for(int i=1;i<=n;i++)
        f[i][0] = cut(1,i);
    for(int i = 2;i <= n;i++){ //枚举分割为前i位数字 
        for(int a = 1;a <= min(i-1,k);a++){ //枚举有几个乘号 
            for(int b = a;b < i;b++){ //在第几位放乘号 
                 f[i][a] = max(f[i][a],f[b][a-1] * cut(b + 1,i));
            }
        }
    }
    cout<<f[n][k];
    return 0;
}

然后,就是我们的毒瘤最后一题啦

面条切割

这一题涉及到动态规划的本质,但是这一题要用到微积分,所以……

原题链接:Problem - 5984 (hdu.edu.cn)

设长度为x的面条期望为f(x)。显然,当x<d时,f(x)=0。当x>b时,设t为0~x上的坐标值,吃掉t~x上的面条,剩下的面条就是0~t,即吃掉剩下的面条次数期望为f(t) 。dt为一个很小的线元,点落在dt上的概率为\frac{dt}{x},而dt贡献的期望为:dt的长度为t,如上所述,贡献了f(t)的期望。最后我们再把这些相加(积分),得到f(x)=1+\frac{\int_{d}^{x} f(t)dt}{x}。接下来就是解出f(x)了。我们可以对f(x)求个导,然后还原,如下(LateX难打)

于是乎,f(x)=\ln x+C。然后,我们代一个特指进去,随便哪一个都行,最好是x=d,然后得到C=1-\ln d。综上所述,f(x)=\ln \frac{d}{x}+1。代码来啦

#include <bits/stdc++.h>
using namespace std;
int main() {
    int T;
    cin >> T;
    while (T--) {
        double a, b;
        cin >> a >> b;
        if (a <= b)
            cout << "0.000000" << endl;
        else
            cout << fixed << setprecision(6) << 1.0 + log(a / b) << endl;
    }
    return 0;
}

时间复杂度几乎为O(1)!

OK!今天就讲到这里,886

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1469727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号程序员刘同学&#xff0c;回复思科获取下载链接。 实验目的实验环境实验内容MAC地址、IP地址、ARP协议总线型以太网的…

渗透工具——kali中wpscan简介

一、什么是wpscan 1、常用于做用户名枚举爆破 2、WPScan是一个扫描 WordPress 漏洞的黑盒子扫描器&#xff0c;它可以为所有 Web 开发人员扫描 WordPress 漏洞并在他们开发前找到并解决问题。我们还使用了 Nikto &#xff0c;它是一款非常棒的Web 服务器评估工具&#xff0c;…

MySQL数据库调优之关联查询、排序查询、分页查询、子查询、Group by优化

关联查询优化 1.准备工作 CREATE TABLE IF NOT EXISTS type(id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,card INT(10) UNSIGNED NOT NULL,PRIMARY KEY(id));CREATE TABLE IF NOT EXISTS book( bookid INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, card INT(10) UNSIGNED N…

智慧应急与物联网相结合:物联网技术如何提升智慧应急响应能力

目录 一、引言 二、智慧应急与物联网技术的结合 三、物联网技术提升智慧应急响应能力的途径 四、物联网技术在智慧应急中的应用案例 五、物联网技术在智慧应急中面临的挑战与解决方案 挑战一&#xff1a;技术标准与规范不统一 解决方案&#xff1a; 挑战二&#xff1a;…

【考研数学】基础阶段习题1800和660怎么选❓

我建议以1800题为主 1800题包含基础和强化两部分&#xff0c;基础部分题量很大&#xff0c;类型也很全面&#xff0c;并且难度一点也不高&#xff0c;适合基础不好的学生来做。 660题难度比较大&#xff0c;不适合基础阶段做。 660题虽然名字叫基础训练&#xff0c;但是不适…

英语连读技巧15

1. first one – 第一个 连读听起来就像是&#xff1a;【佛斯湾】 连读的音标为&#xff1a; 例句&#xff1a;I don’t want to be the first one there agin. 发音指导&#xff1a;在“first one”的连读中&#xff0c;"t"和"o"之间的连接几乎消失&a…

Java线程池实现原理详解

线程池是什么 线程池&#xff08;Thread Pool&#xff09;是一种基于池化思想管理线程的工具&#xff0c;经常出现在多线程服务器中&#xff0c;如MySQL。 线程过多会带来额外的开销&#xff0c;其中包括创建销毁线程的开销、调度线程的开销等等&#xff0c;同时也降低了计算…

03|Order by与Group by优化

索引顺序依次是 &#xff1a; name,age,position 案例1 EXPLAIN SELECT * FROM employees WHERE name LiLei AND position dev ORDER BY age;分析: 联合索引中只是用到了name字段做等值查询[通过key_len 74可以看出因为name字段的len74]&#xff0c;在这个基础上使用了age进…

sql-labs32关宽字节注入

一、环境 网上有自己找很快 二、如何通关 2.1解释 虚假预编译没有参数绑定的过程&#xff0c;真实预编译有参数绑定的过程 宽字节注入出现的本质就是因为数据库的编码与代码的编码不同&#xff0c;导致用户可以通过输入精心构造的数据通过编码转换吞掉转义字符。 在32关中…

华为HCIP Datacom H12-831 卷24

多选题 1、如图所示&#xff0c;某园区部署OSPF实现网络互通&#xff0c;其中Area1部署为NSSA区域。某工程师为了实现R1访问R4的环回口地址&#xff0c;在R4的OSPF进程中引入直连路由。以下关于该场景的描述,错误的有哪些项? A、在R4引入直连路由后&#xff0c;R1通过转换后的…

Java基于物联网技术的智慧工地云管理平台源码 依托丰富的设备接口标准库,快速接入工地现场各类型设备

目录 风险感知全面化 项目进度清晰化 环境监测实时化 人员管理高效化 工地数字化 数据网络化 管理智慧化 智慧工地平台整体架构 1个可扩展监管平台 2个应用端 3方数据融合 N个智能设备 智慧工地的远程监管&#xff0c;是工地负责人掌握施工现场情况的必要手段&…

第6.4章:StarRocks查询加速——Colocation Join

目录 一、StarRocks数据划分 1.1 分区 1.2 分桶 二、Colocation Join实现原理 2.1 Colocate Join概述 2.2 Colocate Join实现原理 三、应用案例 注&#xff1a;本篇文章阐述的是StarRocks-3.2版本的Colocation Join 官网文章地址&#xff1a; Colocate Join | StarRoc…

JAVA算法和数据结构

一、Arrays类 1.1 Arrays基本使用 我们先认识一下Arrays是干什么用的&#xff0c;Arrays是操作数组的工具类&#xff0c;它可以很方便的对数组中的元素进行遍历、拷贝、排序等操作。 下面我们用代码来演示一下&#xff1a;遍历、拷贝、排序等操作。需要用到的方法如下 public…

SpringMVC 学习(五)之域对象

目录 1 域对象介绍 2 向 request 域对象共享数据 2.1 通过 ServletAPI (HttpServletRequest) 向 request 域对象共享数据 2.2 通过 ModelAndView 向 request 域对象共享数据 2.3 通过 Model 向 request 域对象共享数据 2.4 通过 map 向 request 域对象共享数据 2.5 通过…

音视频数字化(数字与模拟-电影)

针对电视屏幕,电影被称为“大荧幕”,也是娱乐行业的顶尖产业。作为一项综合艺术,从被发明至今,近200年的发展史中,无人可以替代,并始终走在时代的前列。 电影回放的原理就是“视觉残留”,也就是快速移过眼前的画面,会在人的大脑中残留短暂的时间,随着画面不断地移过,…

智慧城市,未来已来:数字中国建设中的创新实践

随着数字技术的飞速发展&#xff0c;中国正迎来一个全新的智慧城市时代。在这个时代&#xff0c;城市的每一个角落都充满了科技的气息&#xff0c;人们的生活也因此变得更加便捷、高效和美好。今天&#xff0c;就让我们一起走进这个充满未来感的智慧城市&#xff0c;探索数字中…

onlyoffice api开发

编写代码 按照https://api.onlyoffice.com/editors/basic编写代码 <html> <head><meta charset"UTF-8"><meta name"viewport"content"widthdevice-width, user-scalableno, initial-scale1.0, maximum-scale1.0, minimum-scal…

长短连接对压测的影响有多大

【引言】 当我们进行压力测试时&#xff0c;长短连接是一个非常重要的参数。但是&#xff0c;你知道吗&#xff1f;长短连接对于压测结果有着非常大的影响&#xff01;如果你不理解这个参数&#xff0c;那么你的压测结果可能会出现严重的偏差。 在这篇文章中&#xff0c;我将…

使用 yarn 的时候,遇到 Error [ERR_REQUIRE_ESM]: require() of ES Module 怎么解决?

晚上回到家&#xff0c;我打开自己的项目&#xff0c;执行&#xff1a; cd HexoPress git pull --rebase yarn install yarn dev拉取在公司 push 的代码&#xff0c;然后更新依赖&#xff0c;最后开始今晚的开发时候&#xff0c;意外发生了&#xff0c;竟然报错了&#xff0c;…

吴恩达deeplearning.ai:Tensorflow训练一个神经网络

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai 在之前的博客中。我们陆续学习了各个方面的有关深度学习的内容&#xff0c;今天可以从头开始训练一个神经网络了。 Tensorflow训练神经网络模型 我们使用之前用过的例子&#xff1a; 这个神经…