L3-001凑零钱题解

L3-001凑零钱

韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 10000 枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。

输入格式:
输入第一行给出两个正整数:N(≤10000 )是硬币的总个M(≤10​0 )是韩梅梅要付的款额。第二行给出 N 枚硬币的正整数面值。数字间以空格分隔。

输出格式:
在一行中输出硬币的面值 V​1​​ ≤V​2≤⋯≤Vk,满足条件 V1 +V2+…+Vk=M。数字间以 1 个空格分隔,行首尾不得有多余空格。若解不唯一,则输出最小序列。若无解,则输出 No Solution。

注:我们说序列{ A[1],A[2],⋯ }比{ B[1],B[2],⋯ }“小”,是指存在 k≥1 使得 A[i]=B[i] 对所有 i<k 成立,并且 A[k]<B[k]。

输入样例 1:

8 9

5 9 8 7 2 3 4 1

输出样例 1:

1 3 5

输入样例 2:

4 8

7 2 4 3

输出样例 2:

No Solution
 

 

很明显这是一个可行性dp(至少我是这么认为的)

我们只要一个一个考虑 看可以凑出那些面额的硬币就行了

//n为硬币个数
//m为可以价值
//dp[i][j]代表考虑前i个硬币时是否可以凑出来j价值(dp[i][j]的值为0和1,1代表可以0代表不行)
for(int i=0;i<=n;i++)//初始化边界条件  0价值当然是可以了赋值1也是为了考虑某块硬币的价值恰好是j
	{                 //没看懂数据没关系看下面
		dp[i][0]=1;
	}
	for(int i=1;i<=n;i++)//遍历每一块硬币
	{
		for(int j=1;j<=m;j++)//遍历每一种价值
		{
			if(dp[i-1][j-cost[i]]==1&&j-cost[i]>=0)//如果前i-1块硬币可以拼出j-cost[i]
			dp[i][j]=1;                            //那么就把第i块硬币加进去就可以拼出来了j
                                                    //j-cost[i]>=0是防止越界
			else dp[i][j]=dp[i-1][j];//否则就继承i-1的情况可能dp[i-1][j]就是1
		 } 
	}

上面代码看懂了 就解决了3分之一

现在他们要的是输出序列

if(dp[n][m]==1)
{
    while(m)
    {
        if(dp[n-1][m-cost[n]==1)//首先前提是dp[n][m]==1然后考虑前n-1块硬币时可以凑出m-cost[n]
            {                   //那么dp[n][m]就是有前dp[n-1][m-cost[n]]凑出来的
                m-=cost[n];    //找到了一块硬币了 那么我们就要找dp[n-1][m-cost[n]]的方案是啥了
                ans[k++]=cost[n];//记录一下 为了以后输出
            }
         n--;//如果每找到也不用气馁 一定找得到 因为为什么是这样算过来的 第n块不行那么肯定到前面
    }
}

还没有完!!!!

多种方案

又要序列小那我们就排降序 然后找输出序列的时候就会先考虑小面值硬币是不是凑成m的一个部分

于是有

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int cost[10005];
int dp[10005][101];
int ans[10005];
int k=0;
bool compare(int a,int b)
{
	return a>b;
}
int main()
{
	int n;
	int m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>cost[i];
	}
	sort(cost+1,cost+n+1,compare);
	for(int i=0;i<=n;i++)
	{
		dp[i][0]=1;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(dp[i-1][j-cost[i]]==1&&j-cost[i]>=0)
			dp[i][j]=1;
			else dp[i][j]=dp[i-1][j];
		 } 
	}
	if(dp[n][m]==1) 
	{
		 while(m)
		 {
		 	if(dp[n-1][m-cost[n]]==1)//因为dp[n][m]为1 要是不考虑第n块硬币可以出拼出来m-cost[n]那么						//dp[n][m]方案就是由dp[n-1][m-cost[n]]的方案配上第n这块硬币 
			 {						//要考虑m由哪个产生    那么求出dp[n-1][ 
				ans[k++]=cost[n];
				m-=cost[n];
			  } 
			n--;
		 }			
		for(int i=0;i<k-1;i++)
		printf("%d ",ans[i]);
		cout<<ans[k-1]<<endl;
	}
	else printf("No Solution\n");
}

 

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值