最大报销额【暑期集训S题】【0-1背包】

2023-11-11

        这的确是一个背包问题,但是他又有不一样的地方就在于对于实型的处理应该怎么做。

现有一笔经费可以报销一定额度的发票。允许报销的发票类型包括买图书(A类)、文具(B类)、差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元。现请你编写程序,在给出的一堆发票中找出可以报销的、不超过给定额度的最大报销额。 
Input测试输入包含若干测试用例。每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(<=30)是发票张数。随后是 N 行输入,每行的格式为: 
m Type_1:price_1 Type_2:price_2 ... Type_m:price_m 
其中正整数 m 是这张发票上所开物品的件数,Type_i 和 price_i 是第 i 项物品的种类和价值。物品种类用一个大写英文字母表示。当N为0时,全部输入结束,相应的结果不要输出。 
Output对每个测试用例输出1行,即可以报销的最大数额,精确到小数点后2位。 
Sample Input
200.00 3
2 A:23.50 B:100.00
1 C:650.00
3 A:59.99 A:120.00 X:10.00
1200.00 2
2 B:600.00 A:400.00
1 C:200.50
1200.50 3
2 B:600.00 A:400.00
1 C:200.50
1 A:100.00
100.00 0
Sample Output
123.50
1000.00
1200.50

        首先先将一种积累的方法,就是先知道所有可以可以报销的金额的总和,然后现在的背包就变成了放弃几个数而不再是要拿几个数,但是原理是一样的。

他有两类主要函数:

一:

        double temp=0;
        int v[50]={0};
        memset(v, 0, sizeof(v));
        while(sum>Q)
        {
            int now_i=0;
            for(int i=0; i<cnt && !v[i]; i++)
            {
                if(temp<sum-a[i])
                {
                    temp=sum-a[i];
                    now_i=i;
                }
            }
            sum=temp;
            v[now_i]=1;
        }

二:

        while(whole>Q)
        {
            double temp=0;
            for(int i=0; i<cnt; i++)
            {
                temp=temp>(whole-sum[i])?(temp):(whole-sum[i]);
            }
            whole=temp;
        }

亦或者是:

        int v[50]={0};
        memset(v, 0, sizeof(v));
        while(sum>Q)
        {
            double temp=0;
            int now_i=0;
            for(int i=0; i<cnt && !v[i]; i++)
            {
                if(temp<sum-a[i])
                {
                    temp=sum-a[i];
                    now_i=i;
                }
            }
            sum=temp;
            v[now_i]=1;
        }

    这几类做法都是可以的,然而我接下来要写一种背包,就是将dp[i]中的i记录为背包中剩余的物品,dp[0]为满背包情况,每次+1都会丢弃一种最轻的物品,然后寻找所有符合条件中,最大的那个量即可。

主要代码:

        dp[0]=sum;      //接下来每+1表示扔了一个数
        for(int i=0; i<cnt; i++)
        {
            for(int j=N; j>=1; j--)
            {
                if(dp[j-1]) dp[j]=dp[j]>(dp[j-1]-a[i])?dp[j]:(dp[j-1]-a[i]);
                if(dp[j]<=Q && ans<dp[j])
                {
                    ans=dp[j];
                }
            }
        }
        if(dp[0]<=Q)
        {
            ans=dp[0];
        }

 因为主要代码部分相同且可以相互改换(但要注意我的定义的变量名要改)所以我发思路不同的两份的完整代码:

代码一:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
double Q;
int N;
double money[30];
double sum[30];
double ans[30005];
int main()
{
    while(scanf("%lf %d",&Q,&N)&&N)
    {
        double whole=0;      //记录所有可以抵消的发票总价,通过一一排掉小的,得到最接近Q且小于等于Q大的答案。
        int cnt=0;
        memset(ans, 0, sizeof(ans));
        for(int i=0; i<N; i++)
        {
            int n;
            scanf("%d",&n);
            memset(money, 0, sizeof(money));
            bool flag=true;
            for(int j=0; j<n; j++)
            {
                char ss[2];
                double mon;
                getchar();
                scanf("%c%c",&ss[0],&ss[1]);
                scanf("%lf",&mon);
                money[ss[0]-'A']+=mon;
                if(ss[0]-'A'>=3)flag=false;
            }
            if(money[0]<=600&&money[1]<=600&&money[2]<=600&&(money[0]+money[1]+money[2])<=1000&&flag)
            {
                sum[cnt++]=money[0]+money[1]+money[2];
                whole+=money[0]+money[1]+money[2];
            }
        }
        while(whole>Q)
        {
            double temp=0;
            for(int i=0; i<cnt; i++)
            {
                temp=temp>(whole-sum[i])?(temp):(whole-sum[i]);
            }
            whole=temp;
        }
        printf("%.2lf\n",whole);
    }
    return 0;
}

代码二:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define MT(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
double mon[30];
double a[50];
double dp[50];
double Q;
int N;
int main()
{
    while(scanf("%lf %d",&Q,&N)!=EOF)
    {
        if(N==0)break;
        double sum=0;
        double ans=0;
        int cnt=0;
        int n;
        MT(a, 0);
        MT(dp, 0);
        for(int i=0; i<N; i++)      //发票数量
        {
            bool flag=false;
            for(int i=0; i<3; i++) mon[i]=(double)0;
            double temp;
            scanf("%d",&n);
            char s[2];
            for(int j=0; j<n; j++)
            {
                getchar();
                scanf("%c%c",&s[0],&s[1]);
                scanf("%lf",&temp);
                if(s[0]-'A'>2)flag=true;
                mon[s[0]-'A']+=temp;
            }
            if(!flag && mon[0]<=600 && mon[1]<=600 && mon[2]<=600 && mon[0]+mon[1]+mon[2]<=1000)
            {
                a[cnt++]=mon[0]+mon[1]+mon[2];
                sum+=a[cnt-1];
            }
        }
        dp[0]=sum;      //接下来每+1表示扔了一个数
        for(int i=0; i<cnt; i++)
        {
            for(int j=N; j>=1; j--)
            {
                if(dp[j-1]) dp[j]=dp[j]>(dp[j-1]-a[i])?dp[j]:(dp[j-1]-a[i]);
                if(dp[j]<=Q && ans<dp[j])
                {
                    ans=dp[j];
                }
            }
        }
        if(dp[0]<=Q)
        {
            ans=dp[0];
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

最大报销额【暑期集训S题】【0-1背包】 的相关文章

  • 计算机日期函数公式大全,常用的Excel日期函数大全

    Excel日期大家都会用 但是你知道Excel中有多少日期和时间函数吗 Excel为我们提供了大约20个日期和时间函数 这些函数对于处理表格中的日期数据都是非常有用的 下面介绍几个常用的Excel日期函数及其实际应用案例 1 处理动态日期
  • 对区块链的分析理解

    概述 狭义来讲 区块链是一种按照时间顺序将数据区块以链条的方式组合成特定数据结构 并以密码学方式保证的不可篡改和不可伪造的去中心化共享总账 Decentralized shared ledger 能够安全存储简单的 有先后关系的 能在系统内
  • PowerOJ2512: 小红灌溉【染色】

    题目链接 划重点 每个有菜的点只能浇一次且恰好一次 所以意思就是 譬如某个菜的位置是 x y 那么 行x 列y的浇水方案只能使用其中的一个 以此类推 我们给每个有蔬菜的位置的 x y 的x点与y点链接一条无向边 代表x和y只能选择其中的一个
  • MySQL5.7.xx安装卡在Staring the server解决方案--亲测有效

    安装mysql时卡在Staring the server 一般是两个问题 之前安装过mysql 卸载不彻底 你的电脑名称中有中文 我当时用在网上查找的方法 将mysql删除之后 依旧卡在Staring the server这个地方 接着重新
  • 《数据分析原理》:6步解决业务分析难题

    点击上方卡片关注我 回复 8 加入数据分析 领地 一起学习数据分析 持续更新数据分析学习路径相关资料 精彩数据观点 学习资料 数据课程分享 读书会 分享会等你一起来乘风破浪 回复 小飞象 领取数据分析知识大礼包 读书交流 7期 数据分析原理
  • IntelliJ IDEA 下载安装教程,超详细图文教程

    1 IDEA 下载 1 打开浏览器输入https www jetbrains com 进入 Jetbrains官网 点击 Developer Tools 再点击 Intellij IDEA 2 点击中间的 Download 进入IDEA下载
  • 分割预研 -- 2022.5

    MMSegmentation MMSegmentation 标准统一的语义分割框架 非常好的分割开源集成框架 https link zhihu com target https 3A github com open mmlab mmsegm

随机推荐

  • 基于 FBXSDK-Python 的动画操作

    PythonFBXSKD 01 基础的动画操作 1 0 下载安装 FBXSDK 我这里演示的是 FBXSDK 2020 2 只有 py37 版本的 FBXSDK 2020 1 1 版本有 py27 和py33 两个版本 根据自己的pytho
  • kubernetes的configmap格式错乱问题

    一 问题 最近发现configmap资源在查看 o yaml 或者修改 edit 时 存在格式错乱问题 以nginx配置文件为例 通过
  • 点对点隧道协议—PPTP部署配置

    1 虚拟专用网 1 1 PPTP介绍 PPTP Point to Point Tunneling Protocol 即点对点隧道协议 该协议是在PPP协议的基础上开发的一种新的加强型安全协议 支持多协议虚拟专用网 能够经过密码验证协议 PA
  • 微服务方法论02--服务划分规则01

    背景 现在微服务比较流程 那么对于微服务的拆分方法也比较让人困惑 本文从不同的角度切入后以系统的 全面的 统一的方式为各位介绍服务拆分的问题 问题定义 服务划分具体的问题在哪里 服务划分是对于具体技术的选择 是选择使用纵向切割的方式 还是使
  • Java集合详解——TreeSet集合的介绍及其排序

    一 TreeSet集合的自动排序 TreeSet集合的继承结构图 1 TreeSet集合使用红黑树数据结构实现元素的排序和存储 底层实际上是一个TreeMap集合 2 Tree Map集合底层实际上是一个二叉树 3 放到TreeSet集合中
  • oVirt虚拟化平台下重置windows10虚拟机的一次神奇体验

    前言 公司一台win10虚拟机密码被改掉了 尝试各种方式无解 密码都不对 这台机器上数据还比较多 于是有了下面的探索 1 重启机器 2 ovirt平台控制台进入机器 点击输入密码 3 按5次Shift键 4 文件 运行新任务 输入cmd 5
  • gitee错误failed to push some refs to

    问题说明 当我们在github版本库中发现一个问题后 你在github上对它进行了在线的修改 或者你直接在github上的某个库中添加readme文件或者其他什么文件 但是没有对本地库进行同步 这个时候当你再次有commit想要从本地库提交
  • 【STM32】HAL库-ADC

    12位ADC是一种逐次逼近型模拟数字转换器 它有多达18个通道 可测量16个外部和2个内部信号源 各通道的A D转换可以单次 连续 扫描或间断模式执行 ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中 模拟看门狗特性允许应用程序检
  • 商业数据分析的模型

    2 1 KANO分析模型 KANO模型是东京理工大学教授狩野纪昭 Noriaki Kano 发明的对用户需求分类和优先排序的有用工具 该模型是受行为科学家赫兹伯格的双因素理论启发而提出的 体现了产品性能和用户满意之间的非线性关系 主要是通过
  • L3HCTF2021几道简单的签到题

    L3HCTF2021几道简单的签到题 Misc Welcome Web Image1 Web EasyPHP 作者 Hopeace Misc Welcome 第一次做misc的题目 迷迷糊糊的注册之后 进去好像是个聊天室类似的东西 随便点点
  • 学习C语言第6天打卡

    练习1 斐波那契数列 include
  • 数学:关于对向量、矩阵求导常见公式

    对向量 矩阵求导 和对标量求导还是有点区别 特别是转置和不转置 在网上参考了其他资料整理一下 介绍 在矩阵求导中 分为两种布局 分别是分子布局 Numerator Layout 和分母布局 Denominator Layout 考虑 x y
  • 2023年程序员八股文-集群

    一 负载均衡 集群中的应用服务器 节点 通常被设计成无状态 用户可以请求任何一个节点 负载均衡器会根据集群中每个节点的负载情况 将用户请求转发到合适的节点上 负载均衡器可以用来实现高可用以及伸缩性 高可用 当某个节点故障时 负载均衡器会将用
  • O-RAN专题系列-35:管理面-WG4.MP.V07-规范解读-第2章-总体架构

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122473075 目录 第2章 高层的
  • C++不完整类型incomplete type 浅析

    C 不完整类型incomplete type 浅析 类型定义 The following are incomplete types Type void Array of unknown size Arrays of elements tha
  • 跨域的配置

    1 什么是跨域 跨域 指的是浏览器不能执行其他网站的脚本 它是由浏览器的同源策略造成的 是浏览器对javascript施加的安全限制 注意 跨域限制访问 其实是浏览器的限制 同源策略 是指协议 主机 域名 端口都要相同 其中有一个不同都会产
  • OpenCL学习入门

    1 OpenCL概念 OpenCL是一个为异构平台编写程序的框架 此异构平台可由CPU GPU或其他类型的处理器组成 OpenCL由一门用于编写kernels 在OpenCL设备上运行的函数 的语言 基于C99 和一组用于定义并控制平台的A
  • 合肥工业大学数值分析(计算方法)满分实验代码(python实现)

    用到的库 所有实验一共用到了numpy matplotlib pandas这几个常用的科学计算库 以及内置的数学库 正文开始 所有代码如下图 链接在文末 实验一 实验一的第一个实验主要是比较三种差值方法的差异 书上的差不多忘完了 直接上运行
  • 开开心心带你学习MySQL数据库之第四篇

    欢迎各位 gt 点赞 收藏 留言 慢品人间烟火色 闲观万事岁月长 希望我写的博客对你有所帮助 如有不足 请指正 数据库 1 查看数据库里所有的表 show tables 2 创建表 create table 表名 列名 类型 列名 类型 3
  • 最大报销额【暑期集训S题】【0-1背包】

    这的确是一个背包问题 但是他又有不一样的地方就在于对于实型的处理应该怎么做 现有一笔经费可以报销一定额度的发票 允许报销的发票类型包括买图书 A类 文具 B类 差旅 C类 要求每张发票的总额不得超过1000元 每张发票上 单项物品的价值不得