团体天梯赛 L3-001. 凑零钱

L3-001. 凑零钱

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有104枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。

输入格式:

输入第一行给出两个正整数:N(<=104)是硬币的总个数,M(<=102)是韩梅梅要付的款额。第二行给出N枚硬币的正整数面值。数字间以空格分隔。

输出格式:

在一行中输出硬币的面值 V1 <= V2 <= ... <= Vk,满足条件 V1 + V2 + ... + Vk = M。数字间以1个空格分隔,行首尾不得有多余空格。若解不唯一,则输出最小序列。若无解,则输出“No Solution”。

注:我们说序列{A[1], A[2], ...}比{B[1], B[2], ...}“小”,是指存在 k >= 1 使得 A[i]=B[i] 对所有 i < k 成立,并且 A[k] < B[k]。

输入样例1:
8 9
5 9 8 7 2 3 4 1
输出样例1:
1 3 5
输入样例2:
4 8
7 2 4 3
输出样例2:
No Solution

思路:

动态规划,定义dp[i][j]: 从前i种硬币中凑出价值j是否可能.

定义第i种硬币的币值为a[i],状态转移:if(dp[i-1][j])==1 , dp[i][j]=1;

                                                           if(j>=a[i]&&dp[i-1][j-a[i]]==1),dp[i][j]=1;

此时可再用向量vec[j]存储价值一共为j的款额可以由哪几种硬币币值相加得到,记录其编号。当然其中会有多种组合情况,需要不断更新,取最小序列。

AC代码:

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<iomanip>
#include<map>
#include<stack>
#include<set>
using namespace std;
#define N_MAX 10000+100
#define INF 0x3f3f3f3f
int n, m;
bool dp[N_MAX][100 + 10];//从前i种硬币中凑出价值j是否可能
vector<int>vec[100 + 10];
int a[N_MAX];

bool judge(vector<int>vec, vector<int>tmp) {
    int n = vec.size(), m = tmp.size(), i = 0;
    while (i<n&&i<m) {
        if (vec[i] <tmp[i])return false;
        else if (vec[i] > tmp[i])return true;
        i++;
    }
    return true;
}

int main() {
    while (scanf("%d%d", &n, &m) != EOF) {
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= m; i++) {
            vec[i].clear();
        }
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        sort(a + 1, a + n + 1);
        for (int i = 0; i <= n; i++)
            dp[i][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (dp[i - 1][j]) {
                    dp[i][j] = 1;
                }
                if (j >= a[i] && dp[i - 1][j - a[i]]) {
                    vector<int> tmp = vec[j - a[i]];
                    tmp.push_back(a[i]);
                    if (dp[i][j] == 1 && judge(vec[j], tmp)) {//已经有可行方案,则进行比较
                        vec[j] = tmp;
                    }
                    if (dp[i][j] == 0) {//!!!!!
                        dp[i][j] = 1;
                        vec[j] = tmp;
                    }
                }
            }
        }
        if (!dp[n][m])puts("No Solution");
        else
            for (int i = 0; i < vec[m].size(); i++) {
                printf("%d%c", vec[m][i], i + 1 == vec[m].size() ? '
' : ' ');
            }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZefengYao/p/8463698.html