当前位置: 首页 > news >正文

PAT 1068 Find More Coins

在这里插入图片描述
在这里插入图片描述

这一题的意思是说在N个硬币中选择,使得面额等于M,如果有多种情况,输出字典序从小到大排列的顺序,如果没有选择能使得最后的面额等于M那么就输出No Solution
看题意很明显能想出是选与不选,可以采用dfs递归回溯遍历来枚举所有的情况,当出现等于M的序列后就把它放入到ans数组中。
在这个递归回溯的过程中可以采用挂缓存表的方法,即记忆化搜索,
用缓存表,存储dp[cnt][w]即能不能从第cnt个开始,质量为w,凑出最终的序列是M
如果可以的话,就标记为dp[cnt][w]=1;不可以的话,就标记dp[cnt][w]=0,
判断该状态可不可以的方法就是判断序列数有没有增加

if(ans.size()>nowsize) {dp[cnt][w] = 1;} else {dp[cnt][w] = 0;}

因为数据范
围是N<10^4,那么采用dfs是很容易超时的,因此需要剪枝

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>using namespace std;
int N;
int M;
int v[10001];
int dp[10001][100]; 
vector<vector<int>> ans; 
void dfs(int cnt,int w,vector<int>& q)
{if(cnt>N){return;}if(w>M){return ;}if(w==M){ans.push_back(q);return;}if(dp[cnt][w]==1){//说明可以 }if(dp[cnt][w]==0){return ;}int nowsize=ans.size();q.push_back(v[cnt+1]);dfs(cnt+1,w+v[cnt+1],q);q.pop_back();dfs(cnt+1,w,q);if(ans.size()>nowsize) {dp[cnt][w] = 1;} else {dp[cnt][w] = 0;}}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>N>>M;for(int i=1;i<=N;i++){cin>>v[i];}memset(dp,-1,sizeof(dp));vector<int> q;q.push_back(v[1]);dfs(1,v[1],q);q.pop_back();dfs(1,0,q);if(ans.size()==0){cout<<"No Solution";return 0;}for(int i=0;i<ans.size();i++){sort(ans[i].begin(),ans[i].end());}sort(ans.begin(), ans.end());bool flag=0;for(int j=0;j<ans[0].size();j++){if(flag==0){cout<<ans[0][j];flag=1;}else{cout<<" "<<ans[0][j];}}	cout<<endl;return 0;} 

在这里插入图片描述
因为采用的是二维数组来保存,因此容易出现了内存超限。
最合适的方法应该采用dp table的方法,因为题目上的选与不选,每一个硬币只能选一次,这是很明显的01背包
01背包的核心是写出状态转移方程,明确状态转移方程的含义

bool dp[10001][100]; 

dp[N][M]的意思从前N个硬币选出M个,如果能为true,如果不能为false
那么就可以套用01背包的模板了

	for(int i=1;i<=N;i++)//从前i个里面选择{for(int j=0;j<=M;j++)//面值为j{if(v[i]<=j&&dp[i-1][j-v[i]])//如果当前面置是小于等于j,并且前i-1个中能选择出来j-v[i]的面值。{dp[i][j]=true;//}else//如果不能,那么从前i个里面选择面值为j,实际上就相当于从从i-1里面选择面值为j{dp[i][j]=dp[i-1][j];}}} 

要注意的是这样的选择,是无序的,而题目上想让我们输出字典序最小的满足题意的序列。

sort(v+1,v+1+N,cmp);

因此,我们应该在递推状态转移方程前面对硬币面额进行一个从大到小的排序,
为啥要从大到小排序呢,因为我们在后面想得到dp[N][M]必须是逆序,面值的序列是字典序从小到大。

int j=M;for(int i=N;i>=1;i--){if(j>=v[i]&&dp[i-1][j-v[i]]){ans.push_back(v[i]);j-=v[i];}}

当把所有的值放入到序列中后
按题目要求输出即可

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>using namespace std;
int N;
int M;
int v[10001];
bool dp[10001][100]; 
//要清楚这个dp方程的含义
//什么呢,dp[i][j]从前i个中选出质量为j 
//如果能选出就为true,不能为false 
bool cmp(int a,int b)
{return a>b;
}
vector<int> ans;
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>N>>M;for(int i=1;i<=N;i++){cin>>v[i];}sort(v+1,v+1+N,cmp);dp[0][0]=true;//dp[0][1]=false;for(int i=1;i<=N;i++){for(int j=0;j<=M;j++){if(v[i]<=j&&dp[i-1][j-v[i]]){dp[i][j]=true;}else{dp[i][j]=dp[i-1][j];}}} if(dp[N][M]!=true){cout<<"No solution";return 0;}int j=M;for(int i=N;i>=1;i--){if(j>=v[i]&&dp[i-1][j-v[i]]){ans.push_back(v[i]);j-=v[i];}}// sort(ans.begin(),ans.end());for(int i=0;i<ans.size();i++){if(i==0){cout<<ans[i];}else{cout<<" "<<ans[i];}}return 0;} 

时间复杂度O(n)
在空间复杂度上还能进行一个滚动数组优化,把dp表从二维降到一维。这里不做详细的论述了。

http://www.dtcms.com/a/336340.html

相关文章:

  • ACPI TABLE 方式加载device driver--以spi controller为例
  • 认识信号量机制、以及用信号量来实现进程互斥于进程同步
  • 计算机网络 TCP time_wait 状态 详解
  • VirtualBox-4.3.10-93012-Win.exe 安装教程附详细步骤(附安装包下载)
  • 为何她总在关键时“失联”?—— 解密 TCP 连接异常中断
  • TensorRT-LLM.V1.1.0rc1:Dockerfile.multi文件解读
  • LeetCode 刷题【44. 通配符匹配】
  • 多墨智能-AI一键生成工作文档/流程图/思维导图
  • 《WINDOWS 环境下32位汇编语言程序设计》第3章 使用MASM
  • Redis面试精讲 Day 23:Redis与数据库数据一致性保障
  • 什么是回表?
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘scikit-image’问题
  • Hooks useState的使用
  • leetcode热题100——day33
  • 视频内容提取与AI总结:提升学习效率的实用方法
  • 【深度学习新浪潮】近三年图像处理领域无监督学习的研究进展一览
  • 科目二的四个电路
  • 《Vuejs设计与实现》第 14 章(内建组件和模块)
  • 概率dp|math
  • Android中切换语言的方法
  • 基于Netty的高并发WebSocket连接管理与性能优化实践指南
  • ReactNode 类型
  • 第12章《学以致用》—PowerShell 自学闭环与实战笔记
  • “让机器人更智慧 让具身体更智能”北京世界机器人大会行业洞察
  • Python 调试工具的高级用法
  • OJ目录饿
  • Python 基础语法(二)
  • Kubernetes存储迁移实战:从NFS到阿里云NAS完整指南
  • 【踩坑笔记】50系显卡适配的 PyTorch 安装
  • XF 306-2025 阻燃耐火电线电缆检测