Uva 674 Coin Change(水动规)

本文探讨如何使用动态规划解决硬币组合问题,通过有限的硬币面额(1, 5, 10, 25, 50)实现特定金额的多种组合方式。介绍了动态规划的基本思路,并提供了AC代码实现。

好吧,先说一下,我是在做背包的专题,一看到这题还以为时多重背包和完全背包的组合

一开始还想,那两种背包我没有写过耶,这题有难度,然后下手写以下,写着写着发现不太对劲,

然后突然醒悟,这一题压根就不是什么背包问题,就是很水的动态规划题.

题目大意;你有无限张1,5,10,25,50面值的硬币,然后给你一个金额n(1<=n<=7489),问组成他有多少总情况.

思路:dp[j]代表组成j金额的最优方案个数,转移方程: dp[j] += dp[j - num[i]]; (即dp[j]由前面的最优方案推倒所得)


以下时AC代码:(蠢了,这个根本不需要每次都计算,因为动态规划会遍历所有的情况,只需要过一遍,打个表就可以了)

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <ctime>
#include <cmath>

using namespace std;
const int N = 400000;
int num[10];
int dp[N];
int main()
{
	//freopen("/home/user/桌面/in","r",stdin);
	int n;
	num[1]=1; num[2]=5; num[3]=10; num[4]=25; num[5]=50;
	while(scanf("%d",&n)==1){
		int len = 5;
		for(int i=0;i<=n;++i) dp[i]=1;
		for(int i=2;i<=5;++i){
			for(int j=num[i];j<=n;++j){
				dp[j] += dp[j-num[i]];
			}
		}

		printf("%d\n",dp[n]);
	}
	//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
	return 0;
}

航拍图像多类别实例分割数据集 一、基础信息 • 数据集名称:航拍图像多类别实例分割数据集 • 图片数量: 训练集:1283张图片 验证集:416张图片 总计:1699张航拍图片 • 训练集:1283张图片 • 验证集:416张图片 • 总计:1699张航拍图片 • 分类类别: 桥梁(Bridge) 田径场(GroundTrackField) 港口(Harbor) 直升机(Helicopter) 大型车辆(LargeVehicle) 环岛(Roundabout) 小型车辆(SmallVehicle) 足球场(Soccerballfield) 游泳池(Swimmingpool) 棒球场(baseballdiamond) 篮球场(basketballcourt) 飞机(plane) 船只(ship) 储罐(storagetank) 网球场(tennis_court) • 桥梁(Bridge) • 田径场(GroundTrackField) • 港口(Harbor) • 直升机(Helicopter) • 大型车辆(LargeVehicle) • 环岛(Roundabout) • 小型车辆(SmallVehicle) • 足球场(Soccerballfield) • 游泳池(Swimmingpool) • 棒球场(baseballdiamond) • 篮球场(basketballcourt) • 飞机(plane) • 船只(ship) • 储罐(storagetank) • 网球场(tennis_court) • 标注格式:YOLO格式,包含实例分割的多边形坐标,适用于实例分割任务。 • 数据格式:航拍图像数据。 二、适用场景 • 航拍图像分析系统开发:数据集支持实例分割任务,帮助构建能够自动识别和分割航拍图像中各种物体的AI模型,用于地理信息系统、环境监测等。 • 城市
### 功能 `int coinChange(vector<int>& coins, int amount)` 函数的主要功能是解决零钱兑换问题,即给定不同面额的硬币 `coins` 和一个总金额 `amount`,计算出凑成总金额所需的最少硬币个数。若无法凑出总金额,则返回 -1 [^1][^2][^4]。 ### 实现 #### 动态划实现 ```cpp class Solution { public: int coinChange(vector<int>& coins, int amount) { vector<int> dp(amount + 1, amount + 1); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.size(); j++) { if (coins[j] <= i) dp[i] = min(dp[i], dp[i - coins[j]] + 1); } } return dp.back() > amount ? -1 : dp.back(); } }; ``` 上述代码使用动态划的思想,创建一个长度为 `amount + 1` 的数组 `dp`,`dp[i]` 表示凑成金额 `i` 所需的最少硬币个数。初始化 `dp[0] = 0`,因为凑成金额 0 不需要任何硬币。然后通过两层循环,外层循环遍历金额从 1 到 `amount`,内层循环遍历所有硬币。对于每个硬币,如果其面值小于等于当前金额 `i`,则更新 `dp[i]` 为 `dp[i]` 和 `dp[i - coins[j]] + 1` 中的较小值 [^1][^4]。 #### 回溯 + 剪枝实现 ```cpp class Solution { public: int coinChange(vector<int>& coins, int amount) { if (amount == 0) return 0; int ret = INT_MAX; sort(coins.rbegin(), coins.rend()); coinChange(coins, amount, 0, ret, 0); return ret == INT_MAX ? -1 : ret; } void coinChange(vector<int>& coins, int amount, int count, int &ret, int index) { if (amount == 0) { ret = ret < count ? ret : count; return; } if (index == coins.size()) return; for (int k = amount / coins[index]; k >= 0 && k + count < ret; k--) { coinChange(coins, amount - k * coins[index], count + k, ret, index + 1); } } }; ``` 上述代码采用回溯 + 剪枝的方法,先将硬币从大到小排序,然后从最大面额的硬币开始,尽可能多地使用该硬币,若无法凑出金额则回溯。在回溯过程中,若当前使用的硬币数已经超过当前的最优解 `ret`,则不再向下搜索,进行剪枝 [^3]。 ### 优化方案 - **空间优化**:动态划的实现中,由于每次状态转移只依赖于前一个状态,因此可以考虑使用滚动数组等方式进一步优化空间复杂度,但在该问题中,由于主要是一维数组,空间优化效果不明显。 - **剪枝优化**:在回溯 + 剪枝的实现中,剪枝策略是关键。可以根据实际情况进一步优化剪枝条件,减少不必要的搜索。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值