贪心算法

什么是贪心???

贪心对于刚接触的人来说:贪心??什么鬼?
这里给你两种解释:
1,给你三个妹子做女朋友,第一个有钱,第二个有才,第三个很美,你会选第一个?第二个还是第三个,如果你选的第一个,说明你想在未来自己可以少奋斗30年,如果你选的第二个,说明你这人比较有文化,物以类聚嘛,如果第三个……宅男的梦想啊。当然如果是是我,我当然是把三个都选了,嘿嘿,男人有个三妻四妾算正常吧。别问我为什么,问就是我很贪,贪心的贪,我觉得贪心就是贪,看到啥就贪啥,不会管贪了之后,会有什么道德伦理、贪官落网啥的,这就是贪,就是选当前最优的选择。
2,顾眼前:

遵循某种规则,不断(贪心的)选取当前最优策略,最终找到最优解。
难点:当前最优未必是整体最优

3,官方解释:(点击查看)

贪心案例列表

  1. 硬币问题

硬币问题:

有1元、5元、10元、50元、100元、500元的硬币各
c1、c5、c10、c50、c100、c500枚
现在要用这些硬币来支付A元,最少需要多少枚硬币?
假定本题至少存在一种支付方案,
0<=ci<=10^9
0<=A<=10^9

输入:
第一行有六个数字,分别代表从小到大6种面值的硬币个数
第二行为A,代表需要支付的A元
样例:
输入
3 2 1 3 0 2
620
输出:
6

思考
这题求最少需要多少硬币
这题原解是用的递归,我开始也打算用递归的,可是吧,我做不出来呢,刚好我觉得使用迭代还是不错的呢,故我先用迭代法求解,然后再用递归求解,这题算一题两解吧

迭代法

import java.util.Scanner;
public class CoinsQuestion {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int value[] = {1, 5, 10, 50, 100, 500};//每个硬币的面值
		
		//接收题目给出的数字
		int a[] = new int[6];//每个硬币面值的数量
		for(int i = 0; i < 6; i++){
			a[i] = sc.nextInt();
		}
		int n = sc.nextInt();//需要支付的价格
		
		int ans = 0;//ans存储花费的硬币数
		for(int i = 5; i >= 0; i--){
			//编写一个while循环,用于防止硬币的价格大于需要花费的价格
			//PS:总不能你给老板250,老板倒给你250吧
			while(value[i]*a[i] > n){
				a[i]-=1;
			}
			//将每次最大的硬币面值乘以它对应的数量(前提就是硬币总面值不会大于需要支付的价格啦)
			n = n - value[i]*a[i];
			//前面已经说了,ans存储花费的硬币数量
			ans += a[i];
			//这里做一个提前判断,如果需要支付的价格已经支付完了,那就提前退出循环呗,直接走人
			if(n == 0)break;
		}
		
		//最后打印存储花费的硬币数
		System.out.println(ans);
	}
}

迭代法的思路
思路这东西写多了,等你回头再做的时候,发现还是和没写一样,有个屁用,所以个人觉得这种东西有点难写,不过如果不写,感觉有点……

首先需要判断这题的类型:个人认为是现实的模拟题。假如你是老板,这里有个商品的价格为620美元,这时有个妹纸走进店里,说这个620美元的大大大宝石我要了,但是我这里只有六种面值的硬币,分别是1, 5, 10, 50, 100, 500,对应的数量是3 2 1 3 0 2,随便说一下啊我这人比较懒,如果你愿意收620个一块的硬币,那我也是可以给你的,可如果你想从我这里拿走最少的硬币,但是又刚好是620元,那你就得算算了。你好歹也是一个老板啊,就没见过这么矫情的妹子,不过生意嘛,利益第一,于是你就马上打开eclipse,准备敲……
~
怎么敲呢?已知条件肯定是要用上的:
1,六种面值的硬币,且已知对应的数量是多少;2,已知需要支付的金额。
要求:收取最少的硬币!!!
步骤:
1,使用对应的类型接收对应的数据;
2,我已经知道了硬币的数量,那么就是用for循环逐一判断每种硬币
3,要求最少的硬币?当然是越大面额的硬币老子越喜欢了。所以硬币的判断要从从大到小
4,判断需要支付的价格减去每种硬币的数量乘以对应的面值,保证不能为负数,我总不能倒给你钱吧
5,如果需要支付的价格已经等于零了,不好意思妹子,这题我只用了1秒,掏钱吧

递归法

import java.util.Scanner;
public class CoinsQuestion递归 {
	static int value[] = {1, 5, 10, 50, 100, 500};//每个硬币的面值
	static int nums[], P, ans;//分别存储每种硬币的数量、需要支付的价格、存储硬币的花费数
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		//接收题目给出的数字
		nums = new int[6];//每个硬币面值的数量
		for(int i = 0; i < 6; i++){
			nums[i] = sc.nextInt();
		}
		P = sc.nextInt();//需要支付的价格

		//最后打印存储花费的硬币数
		System.out.println(f(5));
	}
	
	static int f(int n){
		if(P==0){//出口呀
			return ans;
		}
		if(n < 0)return 0;
		
		int num1 = P/value[n];//存储最大的面值硬币的数量应该有多少
		int min = Math.min(num1, nums[n]);//判断理论需要的硬币数和实际有的硬币数
		ans += min;//存储本次花费的硬币数量
		P -= value[n]*min;
		
		return f(n-1);//递归呀
	}
}

思路
不知道对没对,我只有一个案例,而且我对于举反例这块还是比较新手的

步骤:
1,这题既然使用递归,那么代码量一般都会比较少的,这种方法比较抽象嘛,而且main方法里一般都是只有接收数据加输出递归方法的返回值的
2,和迭代法差不多,由大到小判断硬币的面值,用理论上需要花费的硬币的数目和实际上硬币的数目之间的最小值,被减去需要花费的价格
3,判断出口:1)如果需要花费的价格等于0,return,如果硬币的数量已经遍历完了……这不就是钱不够或者没零钱嘛,那就说明:妹纸,此物与你有缘无份啊

有时候真的佩服那些老师,这么简单的问题我都需要做这么久,而且写思路的时候会有一种厌烦的感觉,算心情浮躁吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值