首页 > 其他分享 >纸币问题(动态规划)

纸币问题(动态规划)

时间:2024-10-20 09:32:51浏览次数:1  
标签:10 le int 纸币 面额 动态 规划 dp

前言

本蒟蒻今天在洛谷上练动态规划,遂写此篇

在这里插入图片描述

一、纸币问题 1

P2842 纸币问题 1

题目描述

某国有 \(n\) 种纸币,每种纸币面额为 \(a_i\) 并且有无限张,现在要凑出 \(w\) 的金额,试问最少用多少张纸币可以凑出来?

输入格式

第一行两个整数 \(n,w\),分别表示纸币的种数和要凑出的金额。
第二行一行 \(n\) 个以空格隔开的整数 \(a_1, a_2, a_3, \dots a_n\) 依次表示这 \(n\) 种纸币的面额。

输出格式

一行一个整数,表示最少使用的纸币张数。

提示

对于 \(40\%\) 的数据,满足 \(n\le 10\),\(w\le 100\);
对于 \(100\%\) 的数据,满足 \(1\le n\le 10^3\),\(1\le a_i \leq w\le 10^4\)。

题解

此题是简单的动态规划,求能构成给定数值的纸币数量的最小值。
\(dp[j]\) 表示前 \(i\) 种面额的纸币构成数值为 \(j\) 的金额所需要的最少纸币数量,初状态赋值为\(-1\),表示数值为 \(j\) 的金额无法得到。
对于当前循环的 \(i,j\),如果 \(dp[j-a[i]]!=0\) ,那么则要考虑由数值为 \(j-a[i]\) 的金额得到数值为 \(j\) 的金额能否更新其最小值。
整个过程只需要注意判定 \(dp[j]\) 是否为 \(-1\) 即可。

代码如下

#include<bits/stdc++.h>
using namespace std;
int n,w,a[1001],dp[10001];
int main()
{
	memset(dp,-1,sizeof(dp));
	cin>>n>>w;
	for(int i=1;i<=n;i++) cin>>a[i];
	dp[0]=0;
	for(int i=1;i<=n;i++)
	for(int j=a[i];j<=w;j++)
	if(dp[j-a[i]]!=0)
	if(dp[j]==-1) dp[j]=dp[j-a[i]]+1;
	else dp[j]=min(dp[j],dp[j-a[i]]+1);
	cout<<dp[w]<<endl;
	return 0;
}

二、纸币问题 2

P2840 纸币问题 2

题目背景

你是一个非常有钱的小朋友。

题目描述

你有 \(n\) 种面额互不相同的纸币,第 \(i\) 种纸币的面额为 \(a_i\) 并且有无限张,现在你需要支付 \(w\) 的金额,求问有多少种方式可以支付面额 \(w\),答案对 \(10^9+7\) 取模。
注意在这里,同样的纸币组合如果支付顺序不同,会被视作不同的方式。例如支付 \(3\) 元,使用一张面值 \(1\) 的纸币和一张面值 \(2\) 的纸币会产生两种方式(\(1+2\) 和 \(2+1\))。

输入格式

第一行两个正整数 \(n,w\),分别表示纸币的种数和要凑出的金额。
第二行一行 \(n\) 个以空格隔开的正整数 \(a_1, a_2, \dots a_n\) 依次表示这 \(n\) 种纸币的面额。

输出格式

一行一个整数,表示支付方式的数量。

提示

对于 \(40\%\) 的数据,满足 \(n\le 10\),\(w\le 100\);
对于 \(100\%\) 的数据,满足 \(1\le n\le 10^3\),\(1\le a_i \le w\le 10^4\)。

其实小朋友并不有钱。

题解

这题困扰了我很久,关键在于支付顺序调换会导致不同支付方式的产生,那么如何 \(dp\) 呢?
先给出状态转移方程

\[dp[i]=\sum_{j=1}^{n}{dp[i-a[j]]}(i>=a[j]) \]

外层循环 \(i=1\dots w\),内层循环 \(j=1\dots n\)
这样是如何将顺序调换考虑在内的呢?
我们可以 将 \(a[j]\) 理解为“最后一个支付的纸币” ,下面来模拟看看:

输入如下:

\(n\) \(w\) \(a[0]\) \(a[1]\) \(a[2]\) \(a[3]\) \(a[4]\) \(a[5]\) \(a[6]\)
\(6\) \(15\) \(0\) \(1\) \(5\) \(10\) \(20\) \(50\) \(100\)

模拟如下:

$$i$$ $$0$$ $$1$$ $$2$$ $$3$$ $$4$$ $$5$$ $$6$$
$$dp[i]$$ \(1\) \(1\) \(1\) \(1\) \(1\) \(2\) \(3\)
\(i\) 方式1 方式2 方式3
0 \(0\) -- --
1 \(1\)(最后是1) -- --
2 \(1+1\)(最后是1) -- --
3 \(1+1+1\)(最后是1) -- --
4 \(1+1+1+1\)(最后是1) -- --
5 \(1+1+1+1+1\)(最后是1) \(5\) (最后是5) --
6 \(1+1+1+1+1+1\)(最后是1) \(5+1\)(最后是1) \(1+5\)(最后是5)
\(\dots\) \(\dots\) \(\dots\) \(\dots\)

说明:\(dp[0]=1\) 表示支付 \(0\) 元仅一种方式,即不付钱

当 \(dp[0\dots i-1]\) 已经求得所有情况时,仅需考虑求 \(dp[i]\) 的最后一张纸币的面额 \(a[j]\) 即可,因为在计算每一个 \(dp[i]\) 时,已经将所有纸币面额 \(a[j]\) 考虑在内;确定最后一张的面额并进行情况数加和的过程中,已经包含了计算排列的操作。换句话说,\(dp[i-a[j]]\) 已经将所有排列考虑好了,只需要把最后的 \(a[j]\) 加上去,就得到了 \(dp[i]\) 的一种新情况,并且最后不会有漏算的或重复的(如表中 \(i=6\) 时,可以清晰地看到三种情况)。这很好地体现了“动态规划”的意义。
更形象地来说,考虑将 \(6\) 拆成 \(1+5\) 或者 \(5+1\),当最后一个加的是 \(5\)时,前面的包括 \(1\) 在内的所有数已经排列过了,也就是说 \(1\) 已经出现在了除了最后一个位置之外的所有可能位置,那么只需要再加上 \(1\) 在最后位置的情况,\(1\) 的排列就没有遗漏了。

另外注意:好事多%

代码如下

#include<bits/stdc++.h>
using namespace std;
int n,w,a[1001],dp[10001];
const int mod=1e9+7;
int main()
{
    cin>>n>>w;
    for(int i=1;i<=n;i++) cin>>a[i];
    dp[0]=1;
    for(int i=1;i<=w;i++)
    for(int j=1;j<=n;j++)
	{
        if(i-a[j]>=0)
		dp[i]=(dp[i]+dp[i-a[j]])%mod;
    }
    cout<<(dp[w]%mod)<<endl;
    return 0;
}

三、纸币问题 3

P2834 纸币问题 3

题目背景

你是一个非常有钱的小朋友。

注意:本题和《进阶篇》的对应题目,输入格式略有差异。

题目描述

你有 \(n\) 种面额互不相同的纸币,第 \(i\) 种纸币的面额为 \(a_i\) 并且有无限张,现在你需要支付 \(w\) 的金额,请问有多少种纸币组合能恰好支付金额 \(w\),答案对 \(10^9+7\) 取模。

输入格式

第一行两个正整数 \(n,w\),分别表示纸币的种数和要凑出的金额。
第二行一行 \(n\) 个以空格隔开的正整数 \(a_1, a_2, \dots a_n\) 依次表示这 \(n\) 种纸币的面额。

输出格式

一行一个整数,表示能恰好凑齐面额 \(w\) 的纸币组合数量。

提示

对于 \(40\%\) 的数据,满足 \(n\le 10\),\(w\le 100\);
对于 \(100\%\) 的数据,满足 \(1\le n\le 10^3\),\(1\le a_i \le w\le 10^4\)。

其实小朋友并不有钱。

题解

本题是完全背包问题,可以直接用模板,\(dp[j]\) 记录前 \(i\) 种面额的纸币组成数值为 \(j\) 的钱的方案数,每次循环增加一种纸币面额,依次更新 \(dp[1\dots w]\) 即可。(注意取模)

代码如下

#include<bits/stdc++.h>
using namespace std;
int n,w,a[1001],dp[10001];
const int mod=1e9+7;
int main()
{
    cin>>n>>w;
    for(int i=1;i<=n;i++) cin>>a[i];
    dp[0]=1;
    for(int i=1;i<=n;i++)
    for(int j=a[i];j<=w;j++)
    {
    	dp[j]+=dp[j-a[i]]%mod;
		dp[j]%=mod;	
	}
    cout<<(dp[w]%mod)<<endl;
    return 0;
}

四、问题2与问题3的区别

纸币问题2实际上是方案数排列问题,纸币问题3仅仅是方案数组合问题。因此在动态规划上内外层循环略有不同,二者在递推过程中都符合题目要求完成了计算。

( ^ _ ^ ) /

标签:10,le,int,纸币,面额,动态,规划,dp
From: https://www.cnblogs.com/Gcint-from-2024/p/18486939

相关文章

  • 处理R动态链接库确实得问题
    参考文档https://askubuntu.com/questions/1409562/error-while-loading-shared-libraries-libicudata-so-66-libicudata-so-66-and-lib要使用清华镜像源来解决libicu66的问题,可以按照以下步骤更新的sources.list文件:打开sources.list文件:sudogedit/etc/apt/sources......
  • 动态内存管理 (上)
    目录1.为什么要有动态内存分配 2.malloc和free2.1malloc2.11malloc申请空间和数组的空间有什么区别呢?2.2free3.calloc和realloc3.1calloc 3.2realloc 4.常⻅的动态内存的错误4.1对NULL指针的解引⽤操作4.2对动态开辟空间的越界访问 4.3对⾮动态开......
  • 【C语言】动态内存管理(上)
    本篇博客将讲解以下知识点:(1)为什么要有动态内存分配(2)malloc和free1、为什么要有动态内存分配我们已经掌握的内存开辟方式有:intval=40;//向内存中申请4个字节空间存储valchararr[10];//向内存申请10个字节空间 上述的开辟空间的方式有两个特点:(1)空间的开辟......
  • 利用iptables实现端口映射(支持动态域名)
    将下列代码保存到/bin/ddns_portmap.sh#!/bin/bash#检查参数if["$#"-ne2];thenecho"Usage:$0<domain><local_port1:remote_port1,local_port2:remote_port2,...>"exit1fi#从参数获取动态域名和端口映射domain=$1port_mappings=$2#获取......
  • 静态包含、动态包含和重定向
    test.jsp<%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>静态包含和动态包含对比......
  • 【智能算法应用】鸭群算法求解二维路径规划问题
    摘要本文研究了鸭群算法在二维路径规划问题中的应用,旨在解决复杂障碍环境下的最优路径搜索问题。通过模拟鸭群觅食行为,鸭群算法能够有效避开障碍物,找到最短路径。实验结果表明,鸭群算法在路径规划中表现出较快的收敛速度和较优的路径规划效果,适用于多种复杂环境下的路径优化......
  • 【智能算法应用】引力搜索算法求解二维路径规划问题
    摘要引力搜索算法(GSA)是一种基于引力学说的启发式算法,用于解决复杂的优化问题。本文应用GSA于二维路径规划问题,通过优化路径来避开障碍物并达到目标点。实验结果表明,GSA在路径规划中具有良好的表现,尤其在多障碍场景中,其优化路径平滑且避障效果显著。理论引力搜索算法是......
  • 粒子群算法应用——二维栅格路径规划
    粒子群算法详见:粒子群优化算法及应用-CSDN博客目录1栅格地图1.1 什么是栅格地图1.2栅格地图绘制2基本原理3结果展示1栅格地图1.1 什么是栅格地图栅格地图是一种将环境或地图区域均匀划分为一系列大小一致的网格单元,并为每个单元分配特定属性信息的地图表示方法......
  • 【初窥算法】动态规划之背包问题
    背包问题概述背包问题(KnapsackProblem)是计算机科学和运筹学中的一个经典问题,通常描述为:给定一组物品,每种物品都有自己的重量和价值,在限定的最大承重(背包容量)下,如何选择物品使得背包内物品的总价值最大。背包问题有多种表现形式,包括但不限于:0/1背包问题:有n种物品,每种物品......
  • C++ 基础-面试题01(C和C++区别、C结构体和C++结构体区别、C和C++ static区别、a和&a区
    1.C和C++的区别特性CC++编程范式面向过程编程面向对象编程+面向过程编程+泛型编程类和对象不支持类和对象支持类和对象,封装、继承、多态等特性标准库标准库有限,如stdio.h、stdlib.h丰富的标准库,如STL(容器、算法)函数和运算符重载不支持支持内存管理手动管理,使用malloc......