P2725 [USACO3.1] 邮票 Stamps

P2725 [USACO3.1] 邮票 Stamps

题目描述

给一组 $n$ 枚邮票的面值集合和一个上限 $k$ —— 表示信封上能够贴 $k$ 张邮票。请求出最大的正整数 $m$,满足 $1$ 到 $m$ 的面值都可以用不超过 $k$ 张邮票表示出来。

输入格式

输入的第一行是两个整数,分别代表邮票上限 $k$ 和邮票面值数 $n$。

自第二行起,除最后一行外,每行有 $15$ 个整数 $a_i$ ,最后一行的整数个数不超过 $15$,共有 $n$ 个整数,第 $i$ 个整数代表第 $i$ 种邮票的面值 $a_i$。

输出格式

输出一行一个整数代表 $m$。若 $m$ 不存在请输出 $0$。

输入输出样例 #1

输入 #1

5 2
1 3

输出 #1

13

说明/提示

样例输入输出 1 解释

有 $1$ 分和 $3$ 分的邮票;你最多可以贴 $5$ 张邮票。很容易贴出 $1$ 到 $5$ 分的邮资(用 $1$ 分邮票贴就行了),接下来的邮资也不难:

  • $6 = 3 + 3$。
  • $7 = 3 + 3 + 1$。
  • $8 = 3 + 3 + 1 + 1 $。
  • $9 = 3 + 3 + 3 $。
  • $10 = 3 + 3 + 3 + 1 $。
  • $11 = 3 + 3 + 3 + 1 + 1 $。
  • $12 = 3 + 3 + 3 + 3 $。
  • $13 = 3 + 3 + 3 + 3 + 1$。

然而,使用 $5$ 枚 $1$ 分或者 $3$ 分的邮票根本不可能贴出 $14$ 分的邮资。因此,答案为 $13$。

数据规模与约定

对于 $100%$ 的数据,保证 $1 \leq k \leq 200$,$1 \leq n \leq 50$,$1 \leq a_i \leq 10^4$。

说明

题目翻译来自 NOCOW。

题目分析
如果用bfs来做这道题,根据题意,可以将每次拼出的邮资的值看作一个节点
首先给每个节点赋值

点击查看代码
 for(int i = 0; i < n; i++){
            int next = now + stamp[i]; // 尝试使用第 i 种邮票,得到新邮资

同时确保拼出的值用了最少的张数

点击查看代码
if (sheet[next] > sheet[now] + 1 && sheet[now] + 1 <= k) {
                // 确保拼出的邮资用了更少的张数 并且 没有超过k张
                sheet[next] = sheet[now] + 1; // 更新拼出 next 的最少邮票数
                queue[rear++] = next;
            }

题目中要求返回的是连续拼出面值中最大的一个,注意是连续

点击查看代码
//题目要求连续拼出从1到m的邮资并取最大
    for (int i = 1; i < MAXN; i++) {
        if (sheet[i] > k) {
            return i - 1; //返回最大连续的邮资的值
        }
    }
完整代码如下
点击查看代码
#include <stdio.h>

#define MAXN 10000

int sheet[MAXN]; //表示组成面值为m所需的张数
int stamp[52];
int k,n;

int BFS(){
    int queue[MAXN];
    int front = 0, rear = 0;
    queue[rear++] = 0;
    sheet[0] = 0;

    while(front < rear){
        int now = queue[front++]; //当前邮资
        for(int i = 0; i < n; i++){
            int next = now + stamp[i]; // 尝试使用第 i 种邮票,得到新邮资
            if (next >= MAXN)
                continue;

            if (sheet[next] > sheet[now] + 1 && sheet[now] + 1 <= k) {
                // 确保拼出的邮资用了更少的张数 并且 没有超过k张
                sheet[next] = sheet[now] + 1; // 更新拼出 next 的最少邮票数
                queue[rear++] = next;
            }

        }

    }
    //题目要求连续拼出从1到m的邮资并取最大
    for (int i = 1; i < MAXN; i++) {
        if (sheet[i] > k) {
            return i - 1; //返回最大连续的邮资的值
        }
    }
}

int main() {
    scanf("%d %d", &k, &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &stamp[i]);
    }
    for (int i = 0; i < MAXN; i++) {
        sheet[i] = 1e9; //初始化的状态数组,足够大的初始值,表示还没有被更新
    }
    int result = BFS();
    printf("%d\n", result);
    return 0;
}


posted @ 2025-05-17 00:06  sirro1uta  阅读(26)  评论(0)    收藏  举报