优快云题目:凑硬币问题

本文探讨了如何运用回溯法来解决凑硬币的问题,无论涉及2枚还是3枚硬币,该方法都能提供清晰的解决方案。
这是一个背包问题,但是我要的不是这些,第一个给出背包代码的,20分。其他的不给分。

给出我要的结果的,又分。

我要什么结果呢?先看题目。
你有(足够的)5分,2分,1分的硬币,现在要凑出来12分的结果,那么最少的硬币组合是?

结果肯定是 【5 5 2】


那么给你的硬币是 5分的,4分的(虽然我没有见过),1分的,凑8分,怎么凑?
贪婪算法可能给出 【5 1 1 1】,但是显然应该是【4 4】

我现在要的代码 是那10行背包代码。  

而是要能输出需要哪些硬币的结果,比如对于5,4,1凑8这个,你要输出4,4。

我不关注是2枚硬币,还是3枚。


用回溯法求解:

#include <iostream>
#include <vector>

using namespace std;

int array[] = {5, 4, 1};
const int size = sizeof array / sizeof *array;

vector<vector<int> > ivecs;
vector<int> ivec;

void generateCandidates(int *array, int size, int index, int *candidates, int &ncandidate)
{
	if (array == NULL || size <= 0)
		return;

	ncandidate = 0;
	for (int i = index; i < size; i++)
	{
		candidates[i - index] = array[i];
		ncandidate++;
	}
}

bool isSolution(int sum)
{
	if (sum == 0)
		return true;
	else
		return false;
}

void process(vector<vector<int> > &ivecs, vector<int> &ivec)
{
	ivecs.push_back(ivec);
}

void process(int *array, int size, int *states, int &index, vector<vector<int> > &ivecs, vector<int> &ivec, int sum)
{
	if (array == NULL || size <= 0 || states == NULL)
		return;

	if (sum < 0)
	{
		return;
	}

	int candidates[100];
	int ncandidate;
	if (isSolution(sum) == true)
		process(ivecs, ivec);
	else
	{
		generateCandidates(array, size, index, candidates, ncandidate);
		for (int i = 0; i < ncandidate; i++)
		{
			sum -= candidates[i];
			ivec.push_back(candidates[i]);
			for (int m = 0; m < size; m++)
			{
				if (array[m] == candidates[i])
					index = m;
			}
			process(array, size, states, index, ivecs, ivec, sum);
			ivec.pop_back();
			sum += candidates[i];
		}     
	}
}

void main()
{
	int states[size];
	int index = 0;
	int sum = 8;
	process(array, size, states, index, ivecs, ivec, sum);
	int minNumber = 65535;
	int pos;
	for (int i = 0; i < ivecs.size(); i++)
	{
		if (minNumber > ivecs[i].size())
		{
			pos = i;
			minNumber = ivecs[i].size();
		}
	}

	copy(ivecs[pos].begin(), ivecs[pos].end(), ostream_iterator<int>(cout, " "));
}


迭代算法简单易懂

#include <iostream>
#include <vector>

using namespace std;

int array[] = {5, 4, 1};
const int size = sizeof array / sizeof *array;

vector<vector<int> > ivecs;
vector<int> ivec;

void getCoins(int *array, int size, int total)
{
	if (array == NULL || size <= 0)
		return;

	int leftIndex = 0;
	int rightIndex = 0;
	int totalCount = 0;
	int count = 0;
	int value = total;

	while (leftIndex != size)
	{
		while (rightIndex != size)
		{
			count = value / array[rightIndex];
			if (count != 0)
			{
				for (int i = 0; i < count; i++)
					ivec.push_back(array[rightIndex]);
			}
			value = value % array[rightIndex];
			rightIndex++;
		}

		if (value == 0)
		{
			ivecs.push_back(ivec);
			ivec.clear();
		}

		leftIndex++;
		rightIndex = leftIndex;
		value = total;
	}

	int minNumber = 65535;
	int pos;
	for (int i = 0; i < ivecs.size(); i++)
	{
		if (minNumber > ivecs[i].size())
		{
			pos = i;
			minNumber = ivecs[i].size();
		}
	}

	copy(ivecs[pos].begin(), ivecs[pos].end(), ostream_iterator<int>(cout, " "));
}

void main()
{
	int sum = 38;
	getCoins(array, size, sum);
}



为了解决这个问题,我们需要利用数学建模和逻辑推理技巧来找出所有可能的硬币组合。根据题目的要求,我们可以列出以下两个方程来代表问题的数学模型: 参考资源链接:[人民币兑换方式探究:一元五角换硬币](https://wenku.csdn.net/doc/4y6835c3z5?spm=1055.2569.3001.10343) 1. 5x + 2y + z = 150(硬币总价值) 2. x + y + z = 100(硬币总数) 其中x、y、z别代表521硬币的数量。接下来,我们可以用消元法来简化这个问题。首先解出z: z = 100 - x - y 代入总价值方程中得到: 5x + 2y + (100 - x - y) = 150 4x + y = 50 由于每种硬币至少要有一,我们可以确定x, y, z的最小值均为1。然后,我们可以通过举x和y的值来找出满足条件的所有解。根据硬币的面值和总数,我们可以建立以下的举范围: - x(5硬币: 1 <= x <= 29(因为当x=30时,总金额将超过150) - y(2硬币: 1 <= y <= 49(因为当y=50时,5硬币的数量将减少到不足1举过程中,我们需要确保总金额和硬币总数同时满足上述两个方程。例如,如果x=1,我们可以计算y的可能值: 4*1 + y = 50 y = 50 - 4 y = 46 此时z=100-1-46=53。因此,当5硬币12硬币为461硬币53时,满足题目要求。 通过这种方式,我们可以找出所有可能的硬币组合。实际上,这个问题可以通过编写一个简单的程序来自动化举过程,从而快速得到所有可能的解。核心代码如下: ```python for x in range(1, 30): for y in range(1, 50): z = 100 - x - y if 5*x + 2*y + z == 150: print(f 参考资源链接:[人民币兑换方式探究:一元五角换硬币](https://wenku.csdn.net/doc/4y6835c3z5?spm=1055.2569.3001.10343)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值