题目描述
小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 NN 种蒸笼,其中第 ii 种蒸笼恰好能放 A_iAi 个包子。每种蒸笼都有非常多笼,可以认为是无限笼。
每当有顾客想买 XX 个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有 XX 个包子。比如一共有 33 种蒸笼,分别能放 33 、 44 和 55 个包子。当顾客想买 1111 个包子时,大叔就会选 22 笼 33 个的再加 11 笼 55 个的(也可能选出 11 笼 33 个的再加 22 笼 44 个的)。
当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有 33 种蒸笼,分别能放 44 、 55 和 66 个包子。而顾客想买 77 个包子时,大叔就凑不出来了。
小明想知道一共有多少种数目是包子大叔凑不出来的。
输入格式
第一行包含一个整数 NN。(1 \le N \le 100)(1≤N≤100)。
以下 NN 行每行包含一个整数 A_iAi。(1 \le A_i \le 100)(1≤Ai≤100)。
输出格式
一个整数代表答案。如果凑不出的数目有无限多个,输出 INF
。
输入输出样例
输入 #1复制
2 4 5
输出 #1复制
6
输入 #2复制
2 4 6
输出 #2复制
INF
说明/提示
对于样例 11,凑不出的数目包括:1,2,3,6,7,111,2,3,6,7,11。
对于样例 22,所有奇数都凑不出来,所以有无限多个。
蓝桥杯 2017 省赛 A 组 H 题。
#include <stdio.h>
#include <string.h>
#define N 100001
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a%b);
}
//返回多个数的最大公约数;
int max(int a,int b)
{
return a>=b?a:b;
}
//比较大小;
int main()
{
int w[N];
int n;
int dp[N];
memset(dp,0,sizeof(dp));
//把dp数组赋值为0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
//输入每笼包子数目;
int g = w[1];
for(int i = 2 ; i <= n ; i ++)
g = gcd(g,w[i]);
if(g != 1)
{
printf("INF\n");
}
//输出INF的情况;
else
{
dp[0] = 1;
for(int i=1;i<=n;i++)
for(int j=w[i];j<N;j++)
dp[j]=max(dp[j],dp[j-w[i]]);
//背包问题转移方程变形;
int cnt = 0;
for (int i = 1; i < N; i++)
if (dp[i]==0)
cnt++;
printf("%d",cnt);
}
return 0;
}
理解:这道题首先要判断这些蒸笼的包子数的最小公约数,显然,如果最小公约数是1,包子数必然只能取到他们的倍数,则必然有无穷个无法取到。然后运用背包问题转移方程,先对一个数组赋值为0.然后分别对每一种蒸笼进行判断,如果是其倍数,则把数组赋值为1,最后再进行判断,若为0的包子数就是取不到的