zoukankan      html  css  js  c++  java
  • upc组队赛6 Canonical Coin Systems【完全背包+贪心】

    Canonical Coin Systems

    题目描述

    A coin system S is a finite (nonempty) set of distinct positive integers corresponding to coin values, also called denominations, in a real or imagined monetary system. For example, the coin system in common use in Canada is {1, 5, 10, 25, 100, 200}, where 1 corresponds to a 1-cent coin and 200 corresponds to a 200-cent (2-dollar) coin. For any coin system S, we assume that there is an unlimited supply of coins of each denomination, and we also assume that S contains 1,since this guarantees that any positive integer can be written as a sum of (possibly repeated) values in S.
    Cashiers all over the world face (and solve) the following problem: For a given coin system and a positive integer amount owed to a customer, what is the smallest number of coins required to dispense exactly that amount? For example, suppose a cashier in Canada owes a customer 83 cents. One possible solution is 25+25+10+10+10+1+1+1, i.e.,8 coins, but this is not optimal, since the cashier could instead dispense 25 + 25 + 25 + 5 + 1 + 1 + 1, i.e., 7 coins (which is optimal in this case). Fortunately, the Canadian coin system has the nice property that the greedy algorithm always yields an optimal solution, as do the coin systems used in most countries. The greedy algorithm involves repeatedly choosing a coin of the
    largest denomination that is less than or equal to the amount still owed, until the amount owed reaches zero. A coin system for which the greedy algorithm is always optimal is called canonical.
    Your challenge is this: Given a coin system S = {c1, c2, . . . , cn }, determine whether S is canonical or non-canonical. Note that if S is non-canonical then there exists at least one counterexample, i.e., a positive integer x such that the minimum number of coins required to dispense exactly x is less than the number of coins used by the greedy algorithm. An example of a non-canonical coin system is {1, 3, 4}, for which 6 is a counterexample, since the greedy algorithm yields 4 + 1 + 1 (3 coins), but an optimal solution is 3 + 3 (2 coins). A useful fact (due to Dexter Kozen and Shmuel Zaks) is that if S is non-canonical, then the smallest counterexample is less than the sum of the two largest denominations.

    输入

    Input consists of a single case. The first line contains an integer n (2 ≤ n ≤ 100), the number of denominations in the coin system. The next line contains the n denominations as space-separated integers c1 c2 . . . cn, where c1 = 1 and c1 < c2 < . . . < cn ≤ 106.

    输出

    Output “canonical” if the coin system is canonical, or “non-canonical” if the coin system is non-canonical.

    样例输入

    4
    1 2 4 8
    

    样例输出

    canonical
    

    题意

    有n种面额的货币,如果能保证所以金额,用贪心思想算出的货币张数(每次减先大面额的货币)和 正确的货币张数是相同的,就是规范的(输出canonical),如果贪心算出的货币张数比正确算出的多,那就是不规范的(输出non-canonical)

    题解

    正确的货币张数可以通过完全背包算出 转移方程 dp[i] = d[i - a[j] ] + 1;(dp[i]代表剩余金额为i时已经拥有的张数,a[j]代表第j张钱的面额)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    #define rep(i,a,n) for(int i=a;i<n;++i)
    #define readc(x) scanf("%c",&x)
    #define read(x) scanf("%d",&x)
    #define sca(x) scanf("%d",&x)
    #define read2(x,y) scanf("%d%d",&x,&y)
    #define read3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define print(x) printf("%d
    ",x)
    #define mst(a,b) memset(a,b,sizeof(a))
    #define lowbit(x) x&-x
    #define lson(x) x<<1
    #define rson(x) x<<1|1
    #define pb push_back
    #define mp make_pair
    typedef long long ll;
    typedef pair<ll,ll> P;
    const int INF =0x3f3f3f3f;
    const int inf =0x3f3f3f3f;
    const int mod = 1e9+7;
    const int MAXN = 105;
    const int maxn =2000010;
    using namespace std;
    int n;
    int a[maxn],dp[maxn];
    int main(){
      sca(n);
      for(int i = 0; i < n; i++)
        sca(a[i]);
      sort(a,a+n);
      int maxl = a[n - 1] * 2;
      for(int i = 0; i < maxl; i++) dp[i] = INF;
      dp[0] = 0;
      int flag = 1;
      for(int i = 1; i < maxl; i++){
        for(int j = 0; j < n; j++){
          if(a[j] <= i)
            dp[i] = min(dp[i], dp[i - a[j]] + 1);    //背包
        }
        int cnt = 0;
        int sum = i;
        int pos = n - 1;
        while(sum){                         //贪心
          while(sum >= a[pos]){
            sum -= a[pos];
            cnt ++;
          }
          pos--;
        }
        if(cnt > dp[i]) flag = 0; //不等就是不规范
      }
      if(flag) printf("canonical
    ");
      else printf("non-canonical
    ");
      return 0;
    }
    
  • 相关阅读:
    监考
    初步确定五一粤东出行计划
    煤矿粉尘监控系统中心站软件3层设计
    c# 程序调用代码生成数据库
    Socket 一个服务器监听多个客户端 功能实现
    软件开发进度表
    sql server日期时间格式转换字符串简介
    Sql建表和sql语句的注意事项
    分布式设计与开发(一)宏观概述
    分布式设计与开发(四)数据拆分
  • 原文地址:https://www.cnblogs.com/llke/p/10800093.html
Copyright © 2011-2022 走看看