OpenJudge 4120 硬币

总时间限制: 1000ms 内存限制: 262144kB

描述

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

输入

第一行包含两个正整数n和x。(1 <= n <= 200, 1 <= x <= 10000)
第二行从小到大为n个正整数a1, a2, a3 … an (1 <= ai <= x)

输出

第一行是一个整数,即有多少种硬币是必须被使用的。
第二行是这些必须使用的硬币的面值(从小到大排列)。

样例输入

5 18
1 2 3 5 10

样例输出

2
5 10

提示

输入数据将保证给定面值的硬币中至少有一种组合能恰好能够支付X元。
如果不存在必须被使用的硬币,则第一行输出0,第二行输出空行。

容斥定理

计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。

简单来说,对于一种钱,如果没有它,还可以达到想要的钱,它就是不必须的,用01背包写。

AC代码

#include<stdio.h>
#include<string.h>
int dp[1000005];//表示形成i钱数的方案
int ans[1000005];//表示没有j时形成i钱数的方案数,如果方案数>0.那说明j不必要
int a[220];//存放钱的种类
int b[220];//存放必须有的钱币的种类
int main()
{
    int n, m;//钱的种类数和礼物价格
    int count, k;
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);//读入钱币
        memset(dp, 0, sizeof(dp));//初始化dp,即价格为i时可用的方案数
        dp[0] = 1;//0元礼物的方案数为1
        for (int i = 1; i <= n; i++)
        {
            for (int j = m; j >= a[i]; j--)//逆序,典型的0-1背包
            {
                dp[j] = dp[j] + dp[j - a[i]];
                //j是由a[i]和j-a[i]的和,a[i]的方案为1,
                //j-a[i]的方案数为dp[j-a[i]];
            }
        }
        count = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j <= m; j++)
            {
                if (j < a[i])
                    ans[j] = dp[j];
                else
                    ans[j] = dp[j] - ans[j - a[i]];
            }
            if (ans[m] == 0)//缺了j就不行了,那么j是必需的
            {
                b[count++] = a[i];
            }
        }
        printf("%d
", count);
        if (count == 0)
            printf("

");
        else
        {
            for (int i = 0; i < count; i++)
            {
                if (i != count - 1)
                    printf("%d ", b[i]);
                else
                    printf("%d
", b[i]);
            }
        }

    }
}
原文地址:https://www.cnblogs.com/yun-an/p/10964233.html