1068. Find More Coins 解析

本文探讨了一种改进的背包01问题算法,通过回溯技术寻找构成目标值的具体元素组合,并提供了完整的C++实现代码。文章详细解释了如何利用二维数组记录状态,以及如何从后向前遍历以确保正确获取路径。

这个大神算法很厉害 http://blog.youkuaiyun.com/tiantangrenjian/article/details/17334201

看了好久这个算法。转了好久才有点明白其中的味道。。

主要时明白这个两个二维数组的含义。横轴和纵轴所代表的意思。

注释了下程序 应该比较好看懂了。。

………………………………………………更新线………………………………………………

看了背包01问题之后又重新看这个题 感觉很有意思

这个题是背包01问题的改造,虽然w,v一致了但是需要求出路径。

目前发现要回溯路径要从最后往前回溯,不然会添加进别的不对的节点进去。

求最小就需要把整个数组从大往小排序。

稍微更新了下程序,代码更像经典背包01问题了,简洁了点。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>

#define MAXN 10010
#define MAXM 110

using namespace std;


int n,m;
int c[MAXN];
int dp[MAXM];
//int dp[MAXN][MAXM];
bool has[MAXN][MAXM];
vector <int> ans;

bool cmp(int n1 ,int n2){
	return n1 > n2;
}


int main(){

	scanf("%d%d",&n,&m);

	for(int i = 1; i <= n ;i++){
		scanf("%d",&c[i]);
	}

	sort(&c[1],&c[1]+n,cmp);

	memset(dp,0,sizeof(dp));
	memset(has,false,sizeof(has));


	//for(int i = 1; i <= n ;i++){
	//	for(int v = c[i] ; v <= m ; v++){
	//		if(dp[i-1][v] <= (dp[i-1][v-c[i]] + c[i])){
	//			has[i][v] = true;
	//			dp[i][v] = dp[i-1][v-c[i]] + c[i];
	//		}
	//		else
	//			dp[i][v] = dp[i-1][v];
	//	}
	//}

	for(int i = 1;i <= n ;i++){
		for(int v = m; v >= c[i] ; v--){
			if(dp[v] <= dp[v-c[i]] + c[i]){
				dp[v] = dp[v-c[i]] + c[i];
				has[i][v] = true;
			}
		}
	}


	if(dp[m] == m){
		while(m){
			if(!has[n][m])
				n--;
			else{
				ans.push_back(c[n]);
				m -= c[n];
				n--;
			}
		}

		printf("%d",ans[0]);
		for(int i = 1 ;i < ans.size();i++)
			printf(" %d",ans[i]);
		printf("\n");
	}
	else	
		printf("No Solution\n");


	return 0;
}

………………………………………………更新线完………………………………………………


#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

#define maxN 10010
#define maxM 110

using namespace std;


vector <int> patch;
int f[maxN][maxM];
int has[maxN][maxM];
int c[maxN];
int n,m;


bool cmp(int n1, int n2) {
	return n1 > n2;
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &c[i]);
	}

	sort(c + 1, c + n + 1, cmp);


	memset(f, 0, sizeof(f));
	memset(has, false, sizeof(has));

	//
	int sec;
	//加入当前硬币f[i - 1][j - c[i]] + c[i] 不加入硬币f[i-1][j]
	//i为硬币面额 j为当前最大和
	for (int i = 1; i <= n; i++) {//硬币面额
		for (int j = 1; j <= m; j++) {//总和
			if (j - c[i] < 0) { //当前能到的最大值j 比当前硬币还小 硬币不能用
				sec = 0;
			}
			else {
				sec = f[i - 1][j - c[i]] + c[i]; //加上当前硬币能够到达的最大值
			}

			if (sec >= f[i - 1][j]) {//加入硬币大
				has[i][j] = true;
				f[i][j] = sec;
			}
			else {
				f[i][j] = f[i - 1][j];
			}
		}
	}

	if (f[n][m] == m) {
		while (m) {//反向查询
			if (!has[n][m]) { //硬币从小往大查询 没有加入查询下一个
				n--;
			}
			else {//在队列里面
				patch.push_back(c[n]);
				m -= c[n];//减去该硬币大小查询m-c[n]时所需要的硬币
				n--;
			}
		}
		for (int i = 0; i < patch.size() - 1; i++) {
			cout << patch[i] << " ";
		}
		cout << patch[patch.size() - 1] << endl;
	}
	else
		cout << "No Solution" << endl;

	


	return 0;
}


<think>我们对代码 `let clolist = cloneDeep(cstGroupTypeMap[this.laptops].coins)` 进行解析。 1. **变量名 `clolist`**: - 这是一个新声明的变量(使用 `let` 关键字),用于存储深拷贝后的结果。 2. **`cloneDeep` 函数**: - 这是一个深拷贝函数,通常来自像 Lodash 这样的工具库(例如 `_.cloneDeep()`),或者是一个自定义的深拷贝函数。 - 深拷贝的目的是创建一个新对象,完全复制原对象的所有属性值(包括嵌套对象),使得新对象与原对象互不影响。 3. **`cstGroupTypeMap`**: - 这是一个对象(或映射),通过键来访问对应的值。 - 这里使用 `this.laptops` 作为键来获取 `cstGroupTypeMap` 中的某个值。 4. **`this.laptops`**: - `this` 指向当前上下文(可能是类实例、组件实例或对象)。 - `laptops` 是 `this` 的一个属性,可能是字符串、数字或符号(Symbol),用于作为 `cstGroupTypeMap` 的键。 5. **`.coins`**: - 从 `cstGroupTypeMap[this.laptops]` 返回的对象中,访问其 `coins` 属性。 - 假设 `cstGroupTypeMap[this.laptops]` 返回一个对象,该对象有一个名为 `coins` 的属性。 6. **整体流程**: - 首先,获取 `this.laptops` 的值(记为 `key`)。 - 然后,从 `cstGroupTypeMap` 中获取键为 `key` 的值(记为 `obj`)。 - 接着,获取 `obj.coins` 的值(可能是数组、对象或其他类型)。 - 最后,对 `obj.coins` 进行深拷贝,将结果赋值给 `clolist`。 **示例场景**: 假设有以下数据: ```javascript cstGroupTypeMap = { laptop1: { coins: [{ id: 1, value: 100 }, { id: 2, value: 200 }], // ... 其他属性 }, laptop2: { coins: [ ... ], // ... } }; // 假设 this.laptops 的值为 'laptop1' ``` 那么: - `cstGroupTypeMap[this.laptops]` 得到 `{ coins: [{ id:1, ... }, ...] }` - 再取其 `.coins` 得到数组 `[{ id:1, ... }, ...]` - `cloneDeep` 会深拷贝这个数组,生成一个全新的数组(但内容相同),赋值给 `clolist`。 **注意事项**: - 深拷贝是为了避免后续对 `clolist` 的修改影响原数据(因为数组和对象是引用类型)。 - 如果 `cstGroupTypeMap[this.laptops]` 不存在,或者其 `coins` 属性不存在,则可能报错(如访问 `.coins` 时是 `undefined` 或 `null`)。 **潜在问题**: - 需要确保 `cstGroupTypeMap` 已正确定义,且 `this.laptops` 是其中的一个有效键。 - 确保 `cstGroupTypeMap[this.laptops].coins` 是可被深拷贝的数据(如不包含函数、循环引用等特殊结构)。 综上,这行代码的作用是:从 `cstGroupTypeMap` 中根据当前 `laptops` 属性值取出对应的配置对象,然后将其 `coins` 属性进行深拷贝,并将拷贝结果赋值给 `clolist` 变量。[^1] §§相关问题§§ 1. 什么是深拷贝(deep clone)?与浅拷贝(shallow clone)有什么区别? 2. 在JavaScript中,如何实现一个深拷贝函数? 3. Lodash的`_.cloneDeep()`方法如何使用? 4. 如何确保访问嵌套对象属性时的安全性(避免因中间属性不存在而报错)? </think>### 解析代码 `let clolist = cloneDeep(cstGroupTypeMap[this.laptops].coins)` 此代码片段实现了一个**深拷贝操作**,目的是避免原始数据被修改。具体解析如下: #### 1. **核心组件分析** | 代码片段 | 含义 | |---------------------------|----------------------------------------------------------------------| | `cstGroupTypeMap` | 一个映射对象(类似字典),存放不同分组类型的数据结构 | | `this.laptops` | 当前上下文中 `laptops` 属性的值,作为 `cstGroupTypeMap` 的键 | | `cstGroupTypeMap[this.laptops]` | 获取 `laptops` 键对应的分组配置对象(例如笔记本类产品的配置) | | `.coins` | 从分组配置对象中提取 `coins` 属性(可能是积分规则、代币数据等) | | `cloneDeep(...)` | **深拷贝函数**,递归复制所有嵌套数据,生成完全独立的新对象 | | `let clolist = ...` | 将深拷贝结果赋值给新变量 `clolist`,后续操作不影响原始数据 | #### 2. **执行流程** ```mermaid graph TD A[this.laptops] --> B[作为键查询 cstGroupTypeMap] B --> C[获取分组对象] C --> D[提取 .coins 属性] D --> E[深拷贝 coins 数据] E --> F[结果存入 clolist] ``` #### 3. **关键特性** - **深拷贝必要性** 若直接赋值(如 `let list = cstGroupTypeMap[key].coins`),修改 `list` 会影响原始数据。使用 `cloneDeep` 创建独立副本,确保数据隔离[^1]。 - **数据来源** 依赖于 `cstGroupTypeMap` 的结构,示例结构可能是: ```javascript const cstGroupTypeMap = { laptops: { coins: [{ id: 1, type: 'reward' }, { id: 2, type: 'discount' }], // 待拷贝数据 otherProp: ... }, phones: { ... } }; ``` #### 4. **潜在风险** - **空值访问** 若 `this.laptops` 不存在于 `cstGroupTypeMap` 中,或 `.coins` 未定义,会抛出 `TypeError`。建议添加空值保护: ```javascript const coinsData = cstGroupTypeMap[this.laptops]?.coins || []; let clolist = cloneDeep(coinsData); ``` #### 5. **典型应用场景** - **配置隔离**:克隆产品积分规则供用户临时修改,原始配置不受影响[^2] - **状态管理**:在 Vue/React 中复制状态数据,避免直接修改原始 store - **数据加工**:对嵌套数据进行格式化或过滤时保留原始版本 > 深拷贝是解决 JavaScript **引用类型数据共享**的核心手段,尤其适用于嵌套对象或数组[^3]。 --- ### 相关问题 1. 深拷贝(`cloneDeep`)和浅拷贝(`Object.assign`)在性能和使用场景上有何区别? 2. 如何手动实现一个支持循环引用的深拷贝函数? 3. 在 Vue/React 中,哪些场景必须使用深拷贝来操作状态数据? 4. 如何通过 TypeScript 类型系统确保 `cstGroupTypeMap` 的结构安全性?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值