POJ 硬币

题目描述

宇航员 Bob 有一天来到火星上,他有收集硬币的习惯,于是他将火星上所有面值的硬币都收集起来了,一共有  种,每种只有一个:面值分别为 a1,a2,…,an。Bob 在机场看到了一个特别喜欢的礼物,想买来送给朋友 Alice,这个礼物的价格是 X元。Bob 很想知道为了买这个礼物他的哪些硬币是必须被使用的,即Bob 必须放弃收集好的哪些硬币种类。飞机场不提供找零,只接受恰好 X 元。

输入

第一行包含两个正整数 n 和 x (1≤n≤200,1≤x≤10000)(1n200,1x10000)。

第二行从小到大为 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;
 }

 

posted @ 2023-06-07 15:43  o-Sakurajimamai-o  阅读(38)  评论(0)    收藏  举报
-- --