Skip to content

14029: 【原4029】shop

题目

题目描述

author: Kodak 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4029 

Description

Kodak开了一家小店赚外快,因为店小,所以只有n种不同价格的商品卖,不过好在批发商给力,货源充足,所以每种商品都有无限件

因为各种原因,有时候顾客会对购买的总价有特殊的要求,比如计算机科学家泰玛仕一定要总价1024,给小姐姐买礼物的面包需要总价520或者1314,或者纯粹来找茬的张三要买0元商品

但是Kodak店里不一定有1元的商品,所以并不是所有价格都凑得出来,所以他需要一个程序解决能知道某一个总价能否凑出

Input Format

第一行一个数N, N <= 1000

第二行N个数ai,为N件商品的价格,ai <= 20000

第三行一个数M,有特殊要求的顾客个数, M <= 300000

之后M行,每行一个数bi,为该顾客要求的总价数,bi <= 40000000

Output Format

对个顾客的要求输出一行,如果能凑出要求的总价,输出YES,否则输出NO

Sample Input

3
24 48 100
4
0
520
1024
1314

Sample Output

YES
YES
YES
NO

Pangbo13's solution

#include<stack>
#include<iostream>
using namespace std;
#define Inf 0x3f3f3f3f

int main(){
    int N,M,mod,*a,*min;
    bool* done;
    stack<int> buffer;
    scanf("%d",&N);
    a = new int[N];
    for(int i = 0;i<N;i++) scanf("%d",&a[i]);
    mod = a[0];
    min = new int[mod];
    done = new bool[mod];
    for(int i = 0;i<mod;i++){
        done[i] = 0;
        min[i] = Inf;
    }
    min[0]=0;
    buffer.push(0);
    while(buffer.size()){
        int x=buffer.top();
        buffer.pop();
        if(done[x]) continue;
        done[x]=1;
        for(int i=1;i<N;i++){
            int y=(x+a[i])%mod;
            if(min[y]>min[x]+a[i]){
                min[y]=min[x]+a[i];
                done[y] = 0;
                buffer.push(y);
            }
        }
    }
    scanf("%d",&M);
    int aim;
    for(int i=0;i<M;i++){
        scanf("%d",&aim);
        if(aim>=min[aim%mod]) printf("YES\n");
        else printf("NO\n");
    }
}

q4x3's solution

/**
 * 最短路 spfa算法
 * 答案数组中dis[k]存储mod m余k的数中可以被凑出的最小总价
 **/
#include <iostream>
#include <stdio.h>

using namespace std;

int N, a[1010], M, ask[300233], dis[20233], m = 20233, INF = 41000000, que[10100000];
bool vis[20233]; //访问标记 是否在队中

void spfa() {
    int head = 0, rear = 0;
    for(int i = 1;i < m;++ i)
        dis[i] = INF;
    que[head] = 0; ++ rear;
    //队空则结束循环
    while(head < rear) {
        //记录队首
        int cur = que[head];
        //队首出队
        vis[que[head]] = 0;
        ++ head;
        //计算每条边可以到达的节点及路径长度 若短于记录 则更新记录 若vis为0 则入队
        for(int i = 0;i < N;++ i) {
            //计算
            int node = (cur + a[i]) % m;
            int tmpdis = dis[cur] + a[i];
            //判断
            if(tmpdis < dis[node]) {
                //更新
                dis[node] = tmpdis;
                //入队
                if(vis[node] == 0) {
                    que[rear] = node;
                    ++ rear;
                    vis[node] = 1;
                }
            }
        }
    }
}

int main() {
    cin >> N;
    for(int i = 0;i < N;++ i) {
        scanf("%d", &a[i]);
        if(a[i] < m) m = a[i];
    }
    spfa();
    cin >> M;
    for(int i = 0;i < M;++ i) {
        scanf("%d", &ask[i]);
    }
    for(int i = 0;i < M;++ i) {
        if(dis[ask[i] % m] <= ask[i]) printf("YES\n");
        else printf("NO\n");
    }
}

zqy2018's solution

/*
    Hint: use infinite knapsack (the test data is much smaller than you thought)
*/
#include <bits/stdc++.h>
#define INF 2000000000
using namespace std;
typedef long long ll;
int read(){
    int f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
    while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
    return f * x; 
}
int n, m, a[1005], ans[300005], maxi = 0;
bool vis[40000005] = {0};
void init(){
    n = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    m = read();
    for (int i = 1; i <= m; ++i)
        ans[i] = read(), maxi = max(maxi, ans[i]);
    vis[0] = true;
    for (int i = 1; i <= n; ++i){
        int t = a[i];
        for (int j = t; j <= maxi; ++j)
            vis[j] = vis[j] || vis[j - t];
    }
}
void solve(){
    for (int i = 1; i <= m; ++i){
        if (vis[ans[i]])
            printf("YES\n");
        else 
            printf("NO\n");
    }
}
int main(){
    init();
    solve();
    return 0;
}