ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

坑爹的黑店

2022-07-25 08:35:40  阅读:126  来源: 互联网

标签:数字 黑店 坑爹 饮料 算法 这道题 我们 贪心


坑爹的黑店

题目信息

题目备注

  • 题目出处:程序设计大赛
  • 题目类型:数学推导

题目描述

今天小明去了一个风景如画的地方散心,但是自己带的饮料喝完了,小明口渴难耐,见不远处有家小商店,于是跑去买饮料。

小明:“我要买饮料!”

店主:“我们这里有三种饮料,矿泉水1.5元一瓶,可乐2元一瓶,橙汁3.5元一瓶。”

小明:“好的,给我一瓶矿泉水。”

说完他掏出一张N元的大钞递给店主。

店主:“我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿。”

小明:“......”

小明环顾四周,就这一家商店,况且实在太渴了,就决定在这买了。不过小明想,与其把钱当小费送给他还不如自己多买一点饮料,反正早晚都要喝,但是要尽量少让他赚小费。

现在小明希望你能帮他计算一下,最少他要给店主多少小费。

输入

输入数据的第一行是一个整数T(1<=T<=100),代表测试数据的数量。然后是T行测试数据,每个测试数据只包含一个正整数N(1<=N<=10000),N代表小明手中钞票的面值,以分为单位。
注意:商店里只有题中描述的三种饮料。

输出

对于每组测试数据,请你输出小明最少要浪费多少钱给店主作为小费,以分为单位。

样例输入

2
900
250

样例输出

0
50

题解

我的题解

1.初步分析

  这道题我在刚拿到手的时候认为这是一道贪心算法,因此使用贪心算法做了一遍,结果做不出来,因为这道题实际上并不是一道贪心算法题,而是一道数学分析题。现在我们来从头到尾重新分析这道题。

  有三种饮料,分别为1.5元,2元,3.5元,我们有n元钱来买饮料,因为剩下的钱就是小费,因此我们要尽量剩下更少的钱。这道题乍一看确实非常具备成为贪心的潜质,但经过仔细思考之后,我们其实可以发现这道题实际上不是贪心,因为在这道题中,体现出的中心思想是:我们如何让这三个价格组合,进而使它们的价格加和更加接近我们手里的钱,这里侧重的是组合,而且在这道题中饮料并没有上限,这代表我们可以贪欲无穷,在实际生活中,贪欲是由于缺乏导致的,而当我们不缺乏东西,我们的资源是无限的时候,贪欲自然变得没有意义。而在算法题中,当我们选择的东西资源是无限的时候,贪心算法往往需要谨慎的使用,在这里我们就不能使用贪心算法,就和现实生活中一样,我们缺乏的时候往往会由着自己的性子贪婪的能多拿一点算一点;而当我们的资源无限了,我们就需要小心谨慎的分析了,我们应该拿什么,怎么拿,拿多少才对我有好处

  在这道题中我一开始的思路就是贪心算法,我的思路是先疯狂的拿最贵的,然后剩下的钱买不起最贵的之后,就开始拿第二贵的,知道最后的钱连最便宜的饮料也买不起之后,方可结束,这个思路乍一听是没问题的,但是在这个问题中确是错误的:当我们有4块5的时候,我们首先买一瓶3块5的橙汁,还剩下1块钱,然后这1块钱就什么也买不起了,给店家消费1块钱;然而事实是我们可以直接买三平1块5的水,一分小费也不给。使用我这种算法就解决不出来。当我测到这里的时候,我开始怀疑我贪心的方法不对了,诚然我贪心的方法确实不对,因为此时我贪心的不是省钱,而是尽量获得更多昂贵的饮料,这并没有从省钱上考虑,因此我在此时直接换了方向。我下一个贪心的方向换成了我要尽量剩下更少的钱,而我们如何剩下更少的钱呢?我们可以先计算一下我们一直买第一种饮料,一直买第二种饮料,一直买第三种饮料三种情况下剩下的钱最少的情况,然后选择剩下钱最少的那种情况作为第二轮购买的初始金额,这样一来我就能找到最少的策略。这个思路听上去更加靠谱了,但是其时间复杂度也增加了不少,而且,其也能找到错误样例。当我们有6块5的时候,使用我的算法首先会尝试一直购买1块5的饮料的策略,这时会剩下0.5块钱,在尝试只买2块的饮料的时候也会剩下0.5块钱,购买第三种饮料的时候时剩下3块钱,这个策略就会直接被淘汰,然后使用剩下0.5块钱的策略继续计算,然而0.5块钱啥也买不了,因此就留作小费了,但实际上,我们有一个3.5+1.5+1.5 = 6.5的策略不剩下任何小费,但是这个策略就被我忽略了。

  最后我的贪心算法宣布破产,而我最后我也给出了一个最终方案,就是使用递归继续回溯式的策略枚举,这个方法应该可行,但是由于时间复杂度我就没有尝试,以后留作大家的谈资吧。

2.正式分析

  在初步分析基本上错误之后我逐渐得到了正确的结论,这个题的中心思想是我如何得到一个能够让我剩下的钱更少的策略,而不是通过贪心一直得到什么。我们可以将这个问题抽象成一个更加简单的数学模型:用几个数字拼凑成一个更加接近某数的大数。在这个过程中我们会经常用到取模的思想,我们从简单方法类推:当我们想让一个数字通过自身的叠加,进而接近另一个数字的时候,我们往往会使用取模的方式得到叠加次数;当这个数字变成了两个,问题就变得复杂化了,但是我们仍然可以使用数学分析来解决这个问题,我们举一个例子,我们想通过叠加4和6,来接近25,我们如何叠加?我们首先找到4和6的最大公因数,是2,然后我们让4和6都除2,为2和3,2和3两个数字组合,实际上可以组成任何大于3的数字,这是一个神奇的数学规律:当一个奇数和一个偶数进行组合时,可以组合成任何大于最小的数字的数字。而现在我们要为它们的组合乘2,这意味着这两个数字可以组成任何一个大于4的偶数,换言之,当我们手持一个大于4的数字的时候,只要对2求余,剩下的数字就是它们两个组合距离我们手持数字的最短距离。

  现在我们将这个数学规律进行推广,对于两个以上的数字,我们找到它们的最大约数A,只要这三个数字除以A有奇数有偶数,我们就可以用这三个数字组合出任意大于这三个数字中最大的A的倍数(保守情况),当这三个树在除以A相邻的时候,我们可以组合出任意大于这三个数字中最小的A的倍数,而我们想要求一个数字距离这三个数字最近的距离时,直接对A求余即可。

  因此在这个问题中,我们的解法为,通过计算得到三个价格的最大公约数(50),然后我们发现在除以50之后,三个数字并不相邻:3,4,7,但是需要注意的是两个3可以组成6,因此最大的可组合下限是6*50也就是300,因此我们可以得到结论:当我们手持数字大于300的时候,我们可以直接对50进行求余,得到的结果就是三数组合距离我们手持数字的最近距离。而小于这个数字的时候我们需要另行分析。

  基于这个数学思想,我们最终可以得到这样的一个代码:

import java.util.Scanner;
 
public class Main{
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner scanner=new Scanner(System.in);
        int T=scanner.nextInt();
        int num=0;
        for(int i=0;i<T;i++){
            int N=scanner.nextInt();
            if(N<150)
                System.out.println(N);
            else if(N>=300)
                System.out.println(N%50);
            else if(N==150||N==200)
                System.out.println(0);
            else if(150<N&&N<200)
                System.out.println(N%150);
            else
                System.out.println(N-200);
        }
    }
 
}

  上文中的代码是别人写的,以我的思路,还可以将150和200划分到一起,把250这个情况单独拿出来分析也就是:

if(N<150){
	System.out.println(N);
}else if(N<=200){
    System.out.println(N%50);
}else if(N<300){
    System.out.println(N-200);
}else{
    System.out.println(N%50);
}

3.最终分析

  由于发现了一个疑似数学规律的东西,我和另外一个朋友就此规律进行了比较深入的讨论,我们发现这个规律并不是完全正确的,我们发现我们不能使用最大公约树求所有数字组合的最小距离,实际上我们可以把这个数学规律拆成:两个数字的组合相加,在超过一定限度之后会变得步长为1连续,我们发现了几个数字的组合有这种特性:1和任意数字,2和3,3和4,2和7,3和5,其余则不可,我们发现这些数字都有一个特征:最多有一个偶数,必须都为质数,相加不超过9,除1是特殊情况以外其他的数对都符合这个概念。

  需要注意的是这道题还可以使用枚举思想基于动态规划做出来,现在先不讨论这个算法,以后有时间在研究这个动态规划的算法。

其他题解

  目前没有学习到其他更加有价值或者更加优秀的解题方法。

标签:数字,黑店,坑爹,饮料,算法,这道题,我们,贪心
来源: https://www.cnblogs.com/B307-NCAI/p/16516159.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有