USACO-Section4.1 Beef McNuggets【动态规划】

本文探讨了一道有趣的数学问题,即如何通过几种特定数量的包装盒满足顾客购买麦香牛块的需求。给出了完整的解题思路及C++实现代码。

题目描述:

农夫布朗的奶牛们正在进行斗争,因为它们听说麦当劳正在考虑引进一种新产品:麦香牛块。奶牛们正在想尽一切办法让这种可怕的设想泡汤。奶牛们进行斗争的策略之一是“劣质的包装”。“看,”奶牛们说,“如果你只用一次能装3块、6块或者10块的三种包装盒包装麦香牛块,你就不可能满足一次只想买1、2、4、5、7、8、11、14或者17块麦香牛块的顾客了。劣质的包装意味着劣质的产品。”

你的任务是帮助这些奶牛。给出包装盒的种类数N(1<=N<=10)和N个代表不同种类包装盒容纳麦香牛块个数的正整数(1<=i<=256),输出顾客不能用上述包装盒(每种盒子数量无限)买到麦香牛块的最大块数。如果所有购买方案都能得到满足或者不存在不能买到块数的上限,则输出0。 不能买到的最大块数(倘它存在)不超过2,000,000,000。

INPUT FORMAT:

第1行: 包装盒的种类数N

第2行到N+1行: 每个种类包装盒容纳麦香牛块的个数

OUTPUT FORMAT:

输出文件只有一行数字:顾客不能用包装盒买到麦香牛块的最大块数或0(如果所有购买方案都能得到满足或者顾客不能买到的块数没有上限)。


SAMPLE INPUT
3
3
6
10


SAMPLE OUTPUT
17


解题思路:

这道题涉及到数论中的扩展欧几里德定理(用来判断是否无解),当然正常思维也可以想到,当他们的最大公约数大于1时必然发散。然后在公式ax+by=c中,由于x和y大于1,所以c为x*y-x-y(不知道原因),但是由于不止两个数,所以c有可能会被取到,所以c可以作为上限来动态规划,取最小的两个互质正整数即可,所以动态规划数组长度的最大值为255*256-255-256,然后设dp[0]=1,判断dp[j-a[i]]是否为true,直到有Min(a数组最小值)个true时return,问题得解。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#define INF 99999999
using namespace std;
FILE *fin,*fout;
int N,a[11];
bool v[66000];
typedef pair<int,int> P;

int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
int main(){
    fin  = fopen ("nuggets.in", "r");
    fout = fopen ("nuggets.out", "w");
    fscanf(fin,"%d",&N);
    int temp=0;
    for(int i=0;i<N;i++){
        fscanf(fin,"%d",&a[i]);
        if(temp==0)temp=a[i];
        temp=gcd(a[i],temp);
    }
    if(temp>1)fprintf(fout,"%d\n",0); 
    else{
        sort(a,a+N);
        int Min=a[0];
        memset(v,0,sizeof(v));
        int temp=1,ccount=0,ans=0;
        v[0]=true;
        while(1){
            for(int i=0;i<N;i++){
                if(temp<a[i])break;
                else if(v[temp-a[i]]){
                    v[temp]=true;
                    ccount++;
                    break;
                }
            }
            if(ccount>=Min)break;
            if(v[temp]==false){
                ccount=0;
                ans=temp;
            }
            temp++;
        }
        fprintf(fout,"%d\n",ans);
    }
    exit(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值