暴力枚举与总结规律——买不到的数目 (拓展:包子凑数)

买不到的数目

问题描述:
小明开了一家糖果店。

他别出心裁:把水果糖包成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。

数据范围

1N100,
1Ai100

分析:

 

比较《买不到的数目》由两个数求最大凑不出的数,变成了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)    收藏  举报

导航