zoukankan      html  css  js  c++  java
  • 题解 【Uva】硬币问题

    【Uva】硬币问题

    Description

    有n种硬币,面值分别为v1, v2, ..., vn,每种都有无限多。给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值。

    Input

    第一行两个整数,n,S(1≤n≤100, 0≤S≤100000)。
    第二行n个整数vi-1...n(1≤vi≤S)。

    Output

    第一行两个整数,分别表示硬币数目的最小值 a 和最大值 b 。无解则输出 -1 。
    第二行 a 个整数分别表示使用的是第几种硬币。
    第三行 b 个整数分别表示使用的是第几种硬币。

    Sample Input

    6 12
    1 2 3 4 5 6

    Sample Output

    2 12
    6 6
    1 1 1 1 1 1 1 1 1 1 1 1

    Hint

    样例是特殊的,编号和面值是相同的。你编写程序的时候要注意输出编号而不是面值。
    结果按编号升序输出字典序小一种。

    Source

    入门经典,DP,DAG

    解析

    这题一看就要用DP啊啊!

    然而却不知道怎么用qwq!!!

    其实可以把它看成是DAG,

    每一个点(即不同面值)可以通过许多条权值为1的边到达其它点(即增加一枚硬币)。

    因此,只要求最短路和最长路就行了。

    另外,硬币的方案可以用一个father数组来记录,只要在更新路径的时候一起更新就行了。

    上AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    int n,s,v[101],num[100001];
    int dmin[100001]/*最小路径长度*/,famin[100001]/*上一个硬币*/,ansmin[100001]/*打印路径*/,mincnt=0/*硬币个数*/;
    int dmax[100001],famax[100001],ansmax[100001],maxcnt=0;/*max和min一样(下同)*/
    int que[10000001],vis[100001];
    
    int main(){
        scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++){
            scanf("%d",&v[i]);
            num[v[i]]=i;
        }
        vis[0]=1;
        memset(dmin,0x3f,sizeof(dmin));
        memset(dmax,-0x3f,sizeof(dmax));
        dmin[0]=0;dmax[0]=0;
        for(int i=0;i<=s;i++)/*枚举面值*/{
            for(int j=1;j<=n;j++)/*枚举到达当前面值的方式*/{
                int k=i-v[j];
                if(k<0) break;
                if(dmin[i]>dmin[k]+1)/*更新*/{
                    dmin[i]=dmin[k]+1;
                    famin[i]=k;
                }
                if(dmax[i]<dmax[k]+1){
                    dmax[i]=dmax[k]+1;
                    famax[i]=k;
                }
                
            }
        }
        if(dmin[s]==0x3f3f3f3f||dmax[s]==0){
            printf("-1
    ");
            return 0;
        }
        printf("%d %d
    ",dmin[s],dmax[s]);
        for(int i=s;i;i=famin[i])/*打印路径*/{
            int k=famin[i];
            ansmin[++mincnt]=num[i-k];
        }
        sort(ansmin+1,ansmin+mincnt+1);//这一步似乎不需要(重构时懒得删了)
        for(int i=1;i<=mincnt;i++) printf("%d ",ansmin[i]);
        printf("
    ");
        for(int i=s;i;i=famax[i]){
            int k=famax[i];
            ansmax[++maxcnt]=num[i-k];
        }
        sort(ansmax+1,ansmax+maxcnt+1);
        for(int i=1;i<=maxcnt;i++) printf("%d ",ansmax[i]);
        printf("
    ");
    }
  • 相关阅读:
    swift 第十四课 可视化view: @IBDesignable 、@IBInspectable
    swift 第十三课 GCD 的介绍和使用
    swift 第十二课 as 的使用方法
    swift 第十一课 结构体定义model类
    swift 第十课 cocopod 网络请求 Alamofire
    swift 第九课 用tableview 做一个下拉菜单Menu
    swift 第八课 CollectView的 添加 footerView 、headerView
    swift 第七课 xib 约束的优先级
    swift 第六课 scrollview xib 的使用
    swift 第五课 定义model类 和 导航栏隐藏返回标题
  • 原文地址:https://www.cnblogs.com/zsq259/p/10457896.html
Copyright © 2011-2022 走看看