个人笔记:算法讲座3.4——货币系统(完全背包)

本文仅供参考学习使用,谢谢

问题描述:

Alice和Bob分属艾泽拉斯大陆上的两大对立阵营——部落与联盟,两大阵营的货币体系不同,但他们都可以在幽暗城使用铜币进行结算。铜币嘛,当然都一样。这天,Alice和Bob争执起来哪个阵营的货币体系更完美,评价的标准就是M铜以下所有金额,找零用到的最少硬币数目的平均值越小越好。比如货币体系分为金币、银币和铜币,1金=5铜,1银=2铜,所以金额10铜可以用2个金币找零。

  • 输入:

三行,第一行为M,第二行表示部落的货币体系,第三行表示联盟的货币体系。货币体系中第一个数表示硬币种类n,后面的n个数表示各种硬币兑换铜币的数量。

  • 输出:

如果部落的货币体系更好,输出“B”,如果联盟的更好输出“L”、否则输出“=”。

简单的算法(伪动态规划):

#include <stdio.h>
#define max 1000

typedef struct {
    int N;
    int Money[max];
    int solution[max];
}System;

System create(){
    System A;
    for (int i=0; i<max; i++) {
        A.Money[i]=0;
        A.solution[i]=0;
    }
    
    scanf("%d",&A.N);
    for (int i=1; i<=A.N; i++) {
        scanf("%d",&A.Money[i]);
    }
    A.solution[0]=1;
    return A;
}

double workout(System A,int M){
    double evaluate=0;
    
    for (int money=1; money<=M; money++) {
        int sum=0,c=money;
        for (int i=1; i<=A.N; i++) {
            sum+=c/A.Money[i];
            c%=A.Money[i];
        }
        A.solution[money]=sum;
    }
    
    for (int i=1; i<=M; i++) {
        evaluate+=A.solution[i];
    }
    
    return evaluate/M;
}

int main(int argc, const char * argv[]) {
    int M=0;
    double VB=0,VL=0;
    System B,L;
    scanf("%d",&M);
    B=create();
    L=create();
    
    VB=workout(B, M);
    VL=workout(L, M);
    
//    printf("%.2f\t",VB);
//    printf("%.2f\t",VL);
    
    if (VB<VL) {
        printf("B\n");
    } else if (VB>VL) {
        printf("L\n");
    }else {
        printf("=\n");
    }
    return 0;
}

优化后使用动态规划——背包问题(完全背包?)的算法:

简单提示:
在这里插入图片描述

过程演化:

  • 01背包时:(用二维数组作备忘录)

在这里插入图片描述

  • 完全背包时:(用一维数组作备忘录)

有问题
到了我写警告的那一步,你会发现这里出现了一个问题。如果我想要得到 用最少的货币换取 当前金额数值,你会发现每个位置上的数字既要考虑和 F(i,j-c[i])+1)比较谁更小,又要考虑当前k*c[i] 要是最大的。所以会变得很复杂。。。QVQ

所以,最后发现这个问题没法使用完全背包去写(至少我不会。。。。😂😂😂)
还是老老实实用上面写的伪动态规划

问题演变:

求由N种货币组成 1~M之间每个金币额度的 方案数 之和(完全背包问题)(类似于银行的货币系统):

  • 思路分析:

由题意可以得知,需要得到1到M上所有的数字 均由N个数字组成的(Money[N]) 组成方案数目 首先可以将问题简单化为 求
1.只有一种货币时1到M上 每一个数值可以有多少种不同的搭配方案 并将记录存放于一个一维数组便于动态规划
2.再已经有一种货币的基础上再加一种货币,求这两种货币在一起所能给 1到M 提供的不同的搭配方案 ,基于已有的一维数组数据
加上新的组合方案,可以得到这两种货币所能构成的 不同的搭配方案
3.以此类推可以得出N种货币所能构成的搭配方案总数
需要注意的是每一种面值的货币最低可以构成他本身所构成的面值

  • 算法描述:

1.需要申明一个结构体用于存放来自部落和联盟的两种不同的货币体系,需要包含货币面值的种类数N,用于存放N种面值的一维数组Money和
用于记录已经已经构成的不同的搭配方案
2.需要一个create函数建立并输入货币体系的数据,并在输入之前初始化所有数据
3.计算不同的搭配方案时需要分层次去计算一种货币时构成的搭配方案,两种货币时构成的搭配方案 etc
计算当前n种货币面值时 1到M每个数据的搭配方案=从第n个面值开始的所有已存在的搭配方案+(n-当d前面值的)金额已存在的搭配方案
4.将已动态规划存储的1到M上所有的分配方案数求平均 再将部落和联盟的平均值对比 得出平均值小的那个

  • 测试数据:

10
3 7 2 1
3 8 3 1

  • 测试结果:

B

#include <stdio.h>
#define max 1000

typedef struct {
    int N;
    int Money[max];
    int solution[max];
}System;

System create(){
    System A;
    for (int i=0; i<max; i++) {
        A.Money[i]=0;
        A.solution[i]=0;
    }
    
    scanf("%d",&A.N);
    for (int i=1; i<=A.N; i++) {
        scanf("%d",&A.Money[i]);
    }
    A.solution[0]=1;
    return A;
}

int workout(System A,int M){
    int evaluate=0;
    
    //先计算出只有Money[1]的时候的搭配方案,再计算由Money[1]和Money[2]构成的搭配方案,以此类推计算完N种货币的搭配方案
    for (int i=1; i<=A.N; i++) {
        for (int j=A.Money[i]; j<=M; j++) {
            A.solution[j]=A.solution[j]+A.solution[j-A.Money[i]];
        }
    }
    
    for (int i=1; i<=M; i++) {
        evaluate+=A.solution[i];
    }
    
    return evaluate/M;
}

int main(int argc, const char * argv[]) {
    int M=0,VA=0,VB=0;
    System A,B;
    scanf("%d",&M);
    A=create();
    B=create();
    
    VA=workout(A, M);
    VB=workout(B, M);
    
//    printf("%d\t",VB);
//    printf("%d\t",VA);
    if (VA<VB) {
        printf("A\n");
    } else {
        printf("B\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值