暴力枚举与总结规律——买不到的数目 (拓展:包子凑数)
买不到的数目
问题描述:
小明开了一家糖果店。
他别出心裁:把水果糖包成4颗一包和7颗一包的两种。
糖果不能拆包卖。
小朋友来买糖的时候,他就用这两种包装来组合。
当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。
你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。
大于17的任何数字都可以用4和7组合出来。
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。
输入格式
两个正整数 n,m,表示每种包装中糖的颗数。
输出格式
一个正整数,表示最大不能买到的糖数。
数据范围
2≤n,m≤1000,
保证数据一定有解。
输入样例:
4 7
输出样例:17
分析:
先分析样例
样例 4 7 能组成的数k=an+bm:
0 (0个4,0个7)
4 (1,0)
7 (0,1)
8 (2,0)
11(1,1)
12(3,0)
14(0,2)
15(2,1)
16(4,0)
18(1,2)
19(3,1)
....
1.可以看到19=3×4+1×7,也可以看成在12的基础上加7,因此可以从前往后枚举每一个能组成的数(后面依靠前面的结果),枚举到足够大的数。
2.然后再根据 “大于17的任何数字都可以用4和7组合出来”,从后往前找到第一个不能被组合的数就是答案了
采用数组查询会比递归暴搜时间复杂度低一些
#include<stdio.h>
#define MAXN 1000000 int dp[MAXN]; int main() { int n,m; scanf("%d%d",&n,&m); dp[0]=1; for(int i=0;i<MAXN;i++){ if(dp[i-n]&&i>=n||dp[i-m]&&i>=m) dp[i]=1;//加i>=n和i>=m防止下标越界 } for(int i=MAXN-1;i>0;i-=2)//以2为单位递减是因为后来发现结果都是奇数 { if(!dp[i]) { printf("%d",i); break; } } return 0; }
根据暴力枚举的结果,输入几个数据,确定它们的最大不能组合数,我们来总结规律
n m i
2 3 1 i=(2-1)*m-2
2 5 3
2 7 5
2 9 7
2 11 9
2 13 11
3 2 1 i=(3-1)*m-3
3 4 5
3 5 7
3 7 11
3 8 13
3 10 17
3 11 19
3 13 23
4 3 5 i=(4-1)*m-4
4 5 11
4 7 17
4 9 23
4 11 29
4 13 35
4 15 41
5 2 3 i=(5-1)*m-5
5 3 7
5 4 11
5 6 19
5 7 23
5 8 27
5 9 31
5 11 39
5 12 43
111 400 43889 i=(111-1)*m-111
111 398 43669
111 397 43559
111 395 43339
111 394 43229
得出结论:由n和m最大不能组成数i=(n-1)*m-n
#include<stdio.h> int main(){ int n,m; scanf("%d%d",&n,&m); printf("%d",(n-1)*m-n); return 0; }
包子凑数
问题描述:
小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。
每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。
当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。
小明想知道一共有多少种数目是包子大叔凑不出来的。
输入格式
第一行包含一个整数 N。
接下来 N 行,每行包含一个整数 Ai。
输出格式
输出一个整数代表答案。
如果凑不出的数目有无限多个,输出INF。
数据范围
1≤N≤100,
1≤Ai≤100
分析:
比较《买不到的数目》由两个数求最大凑不出的数,变成了n个数求不出数,本质是换汤不换药的,《买不到的数目》的数据保证有解,而《包子凑数》的数据不保证有解,可能有无限个凑不出的数,需要我们考虑。
这里我们需要知道:如果n个数的最大公因数是1,那么 这n个数的线性组合,p * a0 + q * a1 + ... + k * an 它有一个最大凑不出的数,大于这个数之后的所有数都可以被凑出。(裴蜀定理的推广),那么如果最大公因数
最大公因数不是1,就一定有无限个凑不出的数。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=10000; const int M=110; int dp[N]; int n,a[M]; int sum=0; int gcd(int a,int b){//辗转相除法求最大公因数 int temp; temp=max(a,b); b=min(a,b); a=temp; int r=a%b; while(r!=0){ a=b; b=r; r=a%b; } return b; } int main(){ scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&a[i]); } int d=a[0]; for(int i=0;i<n;i++){ d=gcd(d,a[i]);//两两比较查看他们之间的最大公因数 } if(d!=1){//看最大公因数是否为1 printf("INF"); return 0; } dp[0]=1; for(int i=0;i<=N;i++){ for(int j=0;j<n;j++){//相当于判断dp[i-a[0]]||dp[i-a[1]]||...||dp[i-a[n-1]] if(dp[i-a[j]]&&num-a[j]>=0){ dp[i]=1; } } } for(int i=1;i<=N-1;i++){ if(!dp[i]){ sum++; } } printf("%d",sum); return 0; }
posted on 2021-02-07 21:33 wang_dahua 阅读(404) 评论(0) 收藏 举报
浙公网安备 33010602011771号