• 团体天梯赛 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;
    }
  • 相关阅读:
    addChildViewController ipad 中Controller的嵌套和叠加
    Oracle中sign函数和decode函数的使用
    MapReduce调度与执行原理之任务调度
    [置顶] SOLR 4.4 部署
    [笔试] 怪物安全问题
    优先队列的使用——Expedition
    棋盘分割——维数较大的动态规划
    由DAG到背包问题——记忆化搜索和递推两种解法
    硬币问题——记忆化搜索与递推的转换
    DAG上的动态规划---嵌套矩形(模板题)
  • 原文地址:https://www.cnblogs.com/ZefengYao/p/8463698.html
Copyright © 2020-2023  润新知