POJ 硬币
题目描述
宇航员 Bob 有一天来到火星上,他有收集硬币的习惯,于是他将火星上所有面值的硬币都收集起来了,一共有 种,每种只有一个:面值分别为 a1,a2,…,an。Bob 在机场看到了一个特别喜欢的礼物,想买来送给朋友 Alice,这个礼物的价格是 X元。Bob 很想知道为了买这个礼物他的哪些硬币是必须被使用的,即Bob 必须放弃收集好的哪些硬币种类。飞机场不提供找零,只接受恰好 X 元。
输入
第一行包含两个正整数 n 和 x (1≤n≤200,1≤x≤10000)(1≤n≤200,1≤x≤10000)。
第二行从小到大为 n 个正整数 a1,a2,a3,…,an (1≤ai≤10000).
输出
第一行是一个整数,即有多少种硬币是必须被使用的。 第二行是这些必须使用的硬币的面值(从小到大排列)。
输入输出样例
样例输入 #1
5 18
1 2 3 5 10
样例输出 #1
2
5 10
提示
输入数据将保证给定面值的硬币中至少有一种组合能恰好能够支付 X 元。 如果不存在必须被使用的硬币,则第一行输出 0,第二行输出空行。
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n,res,a[N],f[N],ans[N],x,g[N];//f数组是储存i元时的所有方案数,g数组是去掉a[i]的时候的方案总数 int main() { cin>>n>>x; for(int i=0;i<n;i++) cin>>a[i]; f[0]=1;//初始化 for(int i=0;i<n;i++) for(int j=x;j>=a[i];j--) f[j]+=f[j-a[i]];//0-1背包查找方案总数 for(int i=0;i<n;i++) { memset(g,0,sizeof g); for(int j=0;j<=x;j++) if(j>=a[i]) g[j]=f[j]-g[j-a[i]]; //这里我很迷,详细说一下,g[j]是j元是没有a[i]的情况,f[j]是有a[i]的总数 //为什么要减去g而不是f,可以这样想,如果j大一点,此时的j是没有a[i]的方案了 //但是j-a[i]呢?j-a[i]元还是会有a[i],所以必须是减去g,g中永远没有a[i]的参与 else g[j]=f[j];//如果没有a[i].那就相等 if(g[x]==0) ans[res++]=a[i];//如果x的方案是0,那就不是必须的 } cout<<res<<endl; for(int i=0;i<res;i++) cout<<ans[i]<<" "; return 0; }

浙公网安备 33010602011771号