题目:
Description
这款《大富翁》游戏曾经是我的启蒙桌游之一,印象最深的就是那一叠叠花花绿绿的钞票,还有和小伙伴从欢乐买地到撕逼掀桌的搞笑回忆~
当你的对手在一整条街上开满了旅馆(经过时要交过路费),每一次掷骰子都会心惊胆战,一不小心就会损失一个亿的感觉(╯▔皿▔)╯。
最近在逛桌游店的时候,我又忍不住上前搓了一把。
在购买地产、缴纳地税或交过路费时,往往需要支付一定的金额,我们需要用手中的钞票组合出恰好能支付金额的钱数,满足a[1]+a[2]+...+a[k]=M。
眼下我又来到了死亡一条街...看着小伙伴得意洋洋的样子,我心有不甘地拿出了钞票。
当然了支付时还是有一定技巧的,在选择面值时,尽可能选大额的钞票,这样就可以保证剩下足够多的零钱,有更多的金额组合形式,从而减少了不必要的浪费。这里你只需保证让最小的面值尽可能大即可。
现在告诉你初始时yzm10手里各张钞票的面值,你能猜出他是怎么支付的吗?
Input
第一行给出两个正整数:N(1<=N<=10^4)是yzm10手中的钞票数,M(1<=M<=100)是需要支付的金额。
第二行给出N张钞票的非负整数面值(保证在int范围内),数字间以空格分隔。
Output
在一行中按升序输出所需支付的各张钞票的面值,保证让最小的面值尽可能大,数字间以空格分隔。
若无法恰好凑出金额(不足或浪费),则输出-1。
Sample Input 1
4 10 2 3 7 8
Sample Output 1
3 7
Sample Input 2
5 10 2 3 4 4 5
Sample Output 2
2 4 4
Sample Input 3
2 10 5 11
Sample Output 3
-1
Hint
答案可能不唯一,本题采用special judge,输出任意一种即可。
样例1有两种取法(2,8)(3,7),2<3,选第二种。
样例2有两种取法(2,3,5)(2,4,4),因为最小值都为2,两种均满足条件。
题意不解释,解题思路:
01背包,看看是否能恰好装满,然后需要注意的就是在进行背包装卸的时候先排一下序,满足他们的要求,咱们要输出存在最小的值的那组数据,所以我们按照降序排列,之后的先装价值大的,之后就记录路径,(考察重点),保存到数组,然后输出即可。
ac代码:
#include<bits/stdc++.h>
#define maxn 10005
#define maxm 105
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
int num[maxn];
int dp[maxn];
int pre[maxn][maxm];
int ans[maxn];
int cnt=0;
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
int n,m;
// memset(dp,-inf,sizeof(inf));
// dp[0]=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&num[i]);
sort(num,num+n,cmp);
for(int i=0;i<n;i++)
for(int j=m;j>=num[i];j--)
{
if(dp[j]<dp[j-num[i]]+num[i])
{
dp[j]=dp[j-num[i]]+num[i];
pre[i][j]=1;
}
}
// cout<<dp[m]<<endl;
if(dp[m]!=m)
cout<<"-1 -1"<<endl;
else
{
int i=n-1,j=m;
while(j)
{
if(pre[i][j]>0)
{
ans[cnt++]=num[i];
j-=num[i];
}
i--;
}
printf("%d",ans[0]);
for(int i=1;i<cnt;i++)
printf(" %d",ans[i]);
printf("\n");
}
return 0;
}