[凑硬币问题]

healer_kx 2012-09-11 02:31:37
加精
这是一个背包问题,但是我要的不是这些,第一个给出背包代码的,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枚。
...全文
6179 128 打赏 收藏 转发到动态 举报
写回复
用AI写文章
128 条回复
切换为时间正序
请发表友善的回复…
发表回复
zlmlczcmlvsaav 2013-08-05
  • 打赏
  • 举报
回复
#include<IOSTREAM> using namespace std; int main() { int a[10],i=0,target,tot,bb[10],t=1; for(;1;i++) { cin>>a[i]; if(a[i]<=0) {break; i--; } } cin>>target; int mark=0; int b=i; for(i=0;i<=b;i++) { //先输入硬币的种类 5分,然后输入负数进入输入目标数字阶段,确认之后给出结果 if(mark==1) break; else { tot=a[i]; bb[0]=a[i]; t=1; } for(int c=i;c<=b;c++) { tot+=a[c]; if(tot>target) { tot-=a[c]; continue; } else if(tot==target) { bb[t]=a[c]; mark=1; break; } else { bb[t]=a[c]; t++; } } } if(mark==1) { for(i=0;i<=t;i++) { cout<<bb[i]; } } else { cout<<"没有"; } }
zlmlczcmlvsaav 2013-08-05
  • 打赏
  • 举报
回复
#include <vector> #include <stack> #include <iostream> #include <string> int Decrease(int num,std::vector<int> result){ int coin[3]={5,4,1}; for(int i=0;i<sizeof(coin)/sizeof(coin[0]);i++){ if (num>coin[i]){ result.push_back(coin[i]); Decrease(num-coin[i],result); result.pop_back(); }else if(num==coin[i]){ result.push_back(coin[i]); for(int i=0;i<result.size();i++){ std::cout<<result[i]<<","; } std::cout<<"\n"; } } } int main(){ std::vector<int> st; Decrease(8,st); }
double_文 2013-05-27
  • 打赏
  • 举报
回复
#include<iostream> using namespace std; const int a=5,b=4,c=1; int main(){ int total=0; for(int i=2;i>=0;i--) for(int j=2;j>=0;j--) for(int k=12;k>=0;k--) if(a*i+b*j+c*k==8){ cout<<"5元硬币:"<<i<<"个\t2元硬币:"<<j<<"个\t1元硬币:"<<k<<"个"; cout<<endl; total++; } cout<<"共有方法"<<total<<endl; }
double_文 2013-05-27
  • 打赏
  • 举报
回复
#include<iostream> using namespace std; const int a=5,b=2,c=1; int main(){ int total=0; for(int i=3;i>=0;i--) for(int j=6;j>=0;j--) for(int k=12;k>=0;k--) if(a*i+b*j+c*k==12){ cout<<"5元硬币:"<<i<<"个\t2元硬币:"<<j<<"个\t1元硬币:"<<k<<"个"; cout<<endl; total++; } cout<<"共有方法"<<total<<endl; }
x_jefferson 2013-05-04
  • 打赏
  • 举报
回复
各种算法。。。mark学习
lwe304 2013-05-02
  • 打赏
  • 举报
回复
引用 2 楼 zhaoZero41 的回复:
[Quote=引用 1 楼 的回复:] C/C++ code #include <iostream> #include <vector> #include <string> using namespace std; void getResult(vector<int> var, vector<int> &res, int total) { int totalNum = 0; //需要的硬币总数 in…… [/Quote]
#include <iostream>
#include <vector>
#include <string>
using namespace std;


void getResult(vector<int> var, vector<int> &res, int total)
{
	int totalNum = 0;	//需要的硬币总数
	int minNum = 9999;	//最小的硬币总数
	vector<int>::iterator iter = var.begin();
	vector<int>::iterator ivec = iter;
	while(ivec != var.end())
	{
		int tmp = total;
		while(iter != var.end())
		{
			int num = tmp / (*iter);
			totalNum += num;
			tmp = tmp - num * (*iter++);	
		}
		if(tmp != 0)
		{
			totalNum = 0;
			++ivec;
			iter = ivec;
			continue;
		}
		if(totalNum < minNum)
		{
			int t = total;
			minNum = totalNum;
			res.clear();
			res.resize(ivec - var.begin(), 0);
			for(vector<int>::iterator itemp = ivec; itemp != var.end(); ++itemp)
			{
				int num = t / (*itemp);
				res.push_back(num);
				t = t - num * (*itemp);
			}
		}
		totalNum = 0;
		++ivec;
		iter = ivec;
	}
}

bool checkLegal(vector<int> var, vector<int> res, int total)
{
	int result = 0;
	for(vector<int>::size_type i = 0; i < var.size(); ++i)
	{
		result = result + (var[i] * res[i]);
	}
	return (result == total);
}

int main()
{
	vector<int> ivar, iresult;	//ivar用来存贮硬币种类,iresult用来存贮硬币数量
	int total, var;
	cout<<"请输入你需要计算的结果: "<<endl;
	cin>>total;
	cout<<"硬币种类:"<<endl;
	while(cin>>var)
		ivar.push_back(var);
	//此处略过排序,假设硬币是从大到小输入
	iresult.resize(ivar.size(), 0);
	getResult(ivar, iresult, total);
	if(checkLegal(ivar, iresult, total))
	{
		for(vector<int>::size_type i = 0; i < ivar.size(); ++i)
		{
			cout<<"硬币"<<ivar[i]<<"需要"<<iresult[i]<<"枚"<<endl;
		}
	}
	else
	{
		cout<<"分配失败"<<endl;
	}
	
	
	return 0;


}
上面的出了点小问题,请看这份。。
这个结果是错的,例如9,6,4,1凑17,结果应该是9 4 4,程序结果是9 6 1 1
bravebarbarian 2012-10-06
  • 打赏
  • 举报
回复

# f(x, y, z) = ax+by+cz

def get_steps(result, coints = []):
max_cnt = []
steps = []
for coint in coints:
max_cnt.append((result+coint) / coint)
min_step = []
step = max(max_cnt)

a = coints[0]
b = coints[1]
c = coints[2]
for x in range(max_cnt[0]):
for y in range(max_cnt[1]):
for z in range(max_cnt[2]):
sum = a*x+b*y+c*z
if (sum == result):
steps.append((x,y,z))
if (x+y+z) < step:
min_step = [x, y, z]
step = x+y+z
return min_step

if __name__ == '__main__':
print get_steps(200, [12, 7, 5])


上面搞的有问题,又新搞了一个。
wy54072851 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 120 楼 的回复:]

引用 119 楼 的回复:

引用 118 楼 的回复:

引用 115 楼 的回复:

递归,剪枝,求最优解


许多贴代码的不说思路,强烈鄙视,
尤其是说动态规划的,竟然没有写清楚
子问题,以及递推关系,谁能无聊的看懂你的代码。
还是这个好,和我的想法是一样的。

这是一个组合问题,用穷举肯定不好使,时间复杂度太大,
动态规划也许能做,不过问题规模大了,子……
[/Quote]

33秒?? 虽然我只根据楼主的题大概写了个(111楼),第3个数必须为1,所以12 7 5 求200没算出来,但我输入200,12,5,1,一回车就出来了,想不明白你的怎么要算那么长时间,太夸张了~~
huangxy10 2012-09-25
  • 打赏
  • 举报
回复
[Quote=引用 119 楼 的回复:]

引用 118 楼 的回复:

引用 115 楼 的回复:

递归,剪枝,求最优解


许多贴代码的不说思路,强烈鄙视,
尤其是说动态规划的,竟然没有写清楚
子问题,以及递推关系,谁能无聊的看懂你的代码。
还是这个好,和我的想法是一样的。

这是一个组合问题,用穷举肯定不好使,时间复杂度太大,
动态规划也许能做,不过问题规模大了,子问题更多,不合适。
用回溯法,前面……
[/Quote]

好吧,再加一点剪枝,不过性能还是不太好。
3个硬币:
12 7 5
凑200分,需要33秒。
结果是:15*12 + 4*5.
可能使用分支定界搜索方法要好一些。
回溯法本质是DFS,分支定界是用BFS搜。


// MoneyCount.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <vector>
#include <iostream>
#include <algorithm>
#include <time.h>
using namespace std;

vector<int> MoneyKind;
int Total=0;
vector<int> bestSolution; //最优解
int flag=0; //用来判断是否第一次找到可行解
//solution 存有问题的当前解
//total 目前还是需要多少
//x 为增加哪一个硬币
void FindSolution( vector<int> & solution, int total, int x )
{
if( total == x ) //找到了一个可行解
{
if( flag == 0 )
{
bestSolution = solution;
flag = 1;
}
else
{
if( solution.size() < bestSolution.size() )
bestSolution = solution;
}
return;
}

//搜索每一个子节点
total = total - x;

for( int i=0; i<(int)MoneyKind.size(); i++ )
{
solution.push_back( MoneyKind[i] );
if( MoneyKind[i]<=total ) //可行性约束
{
if( flag==1 && solution.size() <= bestSolution.size() )
FindSolution( solution, total ,MoneyKind[i] );
if( flag==0) //没有找到可行解
FindSolution( solution, total ,MoneyKind[i] );
}
solution.pop_back();
}

}

void input()
{
int numKinds=0;
cout << "How many kinds of coins?\n";
cin >> numKinds;
//MoneyKind.resize( numKinds );
cout << "Input all kinds of coins:\n";
for( int i=0; i<numKinds; i++)
{
int m=0;
cin >> m;
MoneyKind.push_back(m);
}
// sort(MoneyKind.begin(), MoneyKind.end());
cout << "Input the total money of coins:\n";
cin >> Total;

}

int _tmain(int argc, _TCHAR* argv[])
{
input();
clock_t begin = clock();
vector<int> solution;
for( int i=0; i<(int)MoneyKind.size(); i++ )
{
solution.push_back( MoneyKind[i] );
if( MoneyKind[i]<=Total ) //可行性约束
{
if( flag==1 && solution.size() <= bestSolution.size() )
FindSolution( solution, Total ,MoneyKind[i] );
if( flag==0 ) //没有找到可行解
FindSolution( solution, Total ,MoneyKind[i] );
}
solution.pop_back();
}

if( flag == 0 )
cout << "NO SOLUTION!" <<endl;
else
{
cout << "SOLUTION IS:\n" ;
sort( bestSolution.begin(),bestSolution.end() );
for( int i=0; i<(int)bestSolution.size(); i++)
cout << bestSolution[i] << " ";
cout <<"\nTime used "<< (clock()-begin)/1000.0 << "s" <<endl;
}

return 0;
}

huangxy10 2012-09-25
  • 打赏
  • 举报
回复
[Quote=引用 118 楼 的回复:]

引用 115 楼 的回复:

递归,剪枝,求最优解


许多贴代码的不说思路,强烈鄙视,
尤其是说动态规划的,竟然没有写清楚
子问题,以及递推关系,谁能无聊的看懂你的代码。
还是这个好,和我的想法是一样的。

这是一个组合问题,用穷举肯定不好使,时间复杂度太大,
动态规划也许能做,不过问题规模大了,子问题更多,不合适。
用回溯法,前面有人说了,适当的剪枝。
剪枝的下界……
[/Quote]

简单写了个回溯法的,没有剪枝的,搜索所有情况。
可以输出所有可行解,这里只输出其中之一的解。


// MoneyCount.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <vector>
#include <iostream>
using namespace std;

vector<int> MoneyKind;
int Total=0;
vector<int> bestSolution; //最优解
int flag=0; //用来判断是否第一次找到可行解
//solution 存有问题的当前解
//total 目前还是需要多少
//x 为增加哪一个硬币
void FindSolution( vector<int> & solution, int total, int x )
{
if( total == x ) //找到了一个可行解
{
if( flag == 0 )
{
bestSolution = solution;
flag = 1;
}
else
{
if( solution.size() < bestSolution.size() )
bestSolution = solution;
}
return;
}

//搜索每一个子节点
total = total - x;
if( total > 0 )
{
for( int i=0; i<MoneyKind.size(); i++ )
{
solution.push_back( MoneyKind[i] );
FindSolution( solution, total ,MoneyKind[i] );
solution.pop_back();
}
}
}

void input()
{
int numKinds=0;
cout << "How many kinds of coins?\n";
cin >> numKinds;
//MoneyKind.resize( numKinds );
cout << "Input all kinds of coins:\n";
for( int i=0; i<numKinds; i++)
{
int m=0;
cin >> m;
MoneyKind.push_back(m);
}
cout << "Input the total money of coins:\n";
cin >> Total;

}

int _tmain(int argc, _TCHAR* argv[])
{
input();
vector<int> solution;
for( int i=0; i<MoneyKind.size(); i++ )
{
solution.push_back( MoneyKind[i] );
FindSolution( solution, Total ,MoneyKind[i] );
solution.pop_back();
}

for( int i=0; i<bestSolution.size(); i++)
cout << bestSolution[i] << " ";

return 0;
}

huangxy10 2012-09-25
  • 打赏
  • 举报
回复
[Quote=引用 115 楼 的回复:]

递归,剪枝,求最优解
[/Quote]

许多贴代码的不说思路,强烈鄙视,
尤其是说动态规划的,竟然没有写清楚
子问题,以及递推关系,谁能无聊的看懂你的代码。
还是这个好,和我的想法是一样的。

这是一个组合问题,用穷举肯定不好使,时间复杂度太大,
动态规划也许能做,不过问题规模大了,子问题更多,不合适。
用回溯法,前面有人说了,适当的剪枝。
剪枝的下界函数可以取还需要的钱/最大的面值。

我见过一个和这个很像的一题:(搜狗实习生笔试题倒数第二题)
有两个数A,B,(-2000<A,B<2000)可以在A上+5,+7,+12,-5,-7,-12六种操作,
问从A到B的最少操作数是多少。
其实也是用6种钱凑出B-A来,不过这里有负硬币。
bravebarbarian 2012-09-25
  • 打赏
  • 举报
回复

def calc_min_step(coins, expectresult):
calc_steps = []
my_steps = []

calc_steps.append(coins[0])
result = calc_steps[0]
index = 0;
while (index < len(coins)):
result = result + coins[index]
if (result < expectresult):
calc_steps.append(coins[index])
elif(result > expectresult):
result = result - coins[index]
index = index + 1
elif(result == expectresult):
calc_steps.append(coins[index])
if (len(my_steps) == 0):
my_steps = calc_steps[0:]
elif (len(my_steps) > len(calc_steps)):
my_steps = calc_steps[0:]
calc_steps.pop()
result = result - coins[index]
index = index + 1
return my_steps

def getsteps(const_coins, expectresult):
steps=[]
coins = []
for i in range(len(const_coins)):
if (i == 0):
coins = const_coins[0:]
else:
coins.append(coins.pop(0))
temp = calc_min_step(coins,expectresult);
if (len(steps) == 0):
steps = temp
if (len(temp)<len(steps)):
steps = temp

return steps

if __name__ == '__main__':
print getsteps([5, 4, 1], 8)


恶心点就恶心点吧,就是遍历,最笨的算法。
xiaosong8584 2012-09-24
  • 打赏
  • 举报
回复
递归,剪枝,求最优解
LAONINGA098 2012-09-24
  • 打赏
  • 举报
回复
很好,收获颇丰
Peerless_Wan 2012-09-24
  • 打赏
  • 举报
回复
学习 了
zuijindeyoushou 2012-09-23
  • 打赏
  • 举报
回复
哈哈哈 很有用呢。。。我会好好看看的。。。
cenge455 2012-09-22
  • 打赏
  • 举报
回复
优化与算法这本书我算是白学了
wy54072851 2012-09-22
  • 打赏
  • 举报
回复
我也来凑凑热闹 :)



// CountNumber.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"

void SetData(int n, int i, int* num, int start)
{
for(int tem = 0; tem < i; tem++)
{
num[start + tem] = n;
}
}

int fun(int total, int* num)
{
int n1 = num[0];
int n2 = num[1];
int n3 = num[2];
int start = 3;
int count = 0;
int count2 = 0;
int num2[32] = {0}; //假设num[32];

/* 确保n1>n2>n3 */
int tem = n1;
if(n2 > n1){n1 = n2; n2 = tem;}
tem = n2;
if(n3 > n2){n2 = n3; n3 = tem;}
tem = n1;
if(n2 > n1){n1 = n2; n2 = tem;}

/* case 1 */
int mod = total % n1;
int div = total / n1;
if(mod == 0)
{
count = div;
SetData(n1, div, num, start);
}
else
{
SetData(n1, div, num, start);
count += div;
start += div;
div = mod / n2;
if(mod % n2 == 0)
{
count += div;
SetData(n2, div, num,start);
}
else
{
SetData(n2, div, num, start);
count += div;
start += div;
mod = mod % n2;
div = mod / n3;
if( mod % n3 == 0)
{
count += div;
SetData(n3, div, num, start);
}
else return 0; //假设只有三个数,n3为1.
}
}

/* case 2 */
mod = total % n1;
div = total / n1;
start = 3;
if(mod == 0)
{
count2 = div;
SetData(n1, div, num2, start);
}
else
{
--div;
SetData(n1, div, num2, start);
count2 = div;
start += div;
mod += n1;
div = mod / n2;
if(mod % n2 == 0)
{
count2 += div;
SetData(n2, div, num2, start);
}
else
{
/* 因为假设n3为1,所以不继续优化了 */
SetData(n2, div, num2, start);
count2 += div;
start += div;
mod = mod % n2;
div = mod / n3;
count2 += div;
SetData(n3, div, num2, start);
}
}

/* 如果case2比case1方案更优,返回case2的数据 */
if( count2 < count)
{
count = count2;
printf("结果:%d\r\n",count);
for(int i = 0; i < count2; i++)
{
printf("%d\r\n",num2[i + 3]);
}
}
else
{
printf("结果:%d\r\n",count);
for(int i = 0; i < count; i++)
{
printf("%d\r\n",num[i + 3]);
}
}

return count;
}

int _tmain(int argc, _TCHAR* argv[])
{
int num[32] = {0};
int total;
int e = 1;

while(e)
{
system("cls");
/* 获取数据 */
printf("请输入总数\r\n");
scanf("%d",&total);
printf("请输入第一个数\r\n");
scanf("%d",&num[0]);
printf("请输入第二个数\r\n");
scanf("%d",&num[1]);
printf("请输入第三个数\r\n");
scanf("%d",&num[2]);

int count = fun(total,num);

printf("继续,请输入1,退出请输入0!\r\n");
scanf("%d",&e);
}

return 0;
}
wjlsmail 2012-09-21
  • 打赏
  • 举报
回复
背包算法的变种
asdf535521 2012-09-19
  • 打赏
  • 举报
回复
我先mark再说。
加载更多回复(79)

64,678

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧