1、钱币找零问题
题目:问题描述:分别有1,5,10,50,100元, 分别有5,2,2,3,5张纸币。问若要支付k元,则最少需要多少张纸币?
解题思路:每次选择支付的纸币时,尽量选择面额最大的,这样每次获得的都是局部最优的选择,直到满足 k 元为止
Java代码如下:
public class GreedyTest1 {
/**
* 题目:问题描述:分别有1,5,10,50,100元,
* 分别有5,2,2,3,5张纸币。问若要支付k元,则需要多少张纸币?
*/
@Test
public void test1(){
int[] money = {1,5,10,50,100};
int[] moneyNum = {5,2,2,3,5};
int k = 316; //待支付的钱数
int count = 0; //需要付款的纸币数目
for(int i=money.length-1;i>=0;i--){ //从最大面额的纸币开始选择,假设面额大小已经按照升序排列
while (k>=money[i] && moneyNum[i]>0){
k -= money[i]; //总额减去当前最大的纸币额度值
moneyNum[i] -= 1;
count += 1;
}
}
System.out.println("最少需要的纸币数量:"+count);
}
}
输出结果:
最少需要的纸币数量:6
2、区间调度问题
题目:假设我们有 n 个区间,区间的起始端点和结束端点分别是[l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。 我们从这 n 个区间中选出一部分区间,这部分区间满足两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢?
比如例子:{6,8},{2,4},{3,5},{1,5},{5,9},{8,10}
思路:每次在选择区间时,要满足当前区间的左端点的数值小于上一个区间的右端点,且当前区间的右端点在剩下的区间中最小
Java代码如下:
public class GreedyTest1 {
/**
* 区间调度问题
* 2、题目:假设我们有 n 个区间,区间的起始端点和结束端点分别是[l1, r1],[l2, r2],[l3, r3],……,[ln, rn]。
* 我们从这 n 个区间中选出一部分区间,这部分区间满足两两不相交(端点相交的情况不算相交),最多能选出多少个区间呢?
* 例子:{6,8},{2,4},{3,5},{1,5},{5,9},{8,10}
* 结果:
* {2,4}
* {6,8}
* {8,10}
*/
@Test
public void test3(){
int[][] data = {{6,8},{2,4},{3,5},{1,5},{5,9},{8,10}};
//先将原始数据 data 按照右端点的数值大小升序排列
boolean flag = true;
for(int i=0;i<data.length-1;i++){
flag = true;
for(int j=i+1;j<data.length;j++){
if(data[j][1]<data[i][1]){
int[] tmp = data[j];
data[j] = data[i];
data[i] = tmp;
flag = false;
}
}
if(flag){
break;
}
}
System.out.println("将原始数据 data 按照右端点的数值大小升序排列: ");
for(int[] d:data){
System.out.print("{"+d[0]+","+d[1]+"}\t");
}
List<int[]> result = new LinkedList<>();
int lr = Integer.MIN_VALUE;
for(int[] d:data){ //每次从data中取出的区间,均为剩下区间中右端点最小的区间
if(d[0]>=lr){ //当前区间若满足左端点小于上一个区间的右端点,则将当前区间加入结果 result 中
result.add(d);
lr = d[1];
}
}
System.out.println("最多能选出的区间数目:"+result.size());
System.out.println("满足最多能选出的区间如下:");
for(int[] d:result){
System.out.print("{"+d[0]+","+d[1]+"}\t");
}
}
}
输出结果:
将原始数据 data 按照右端点的数值大小升序排列:
{2,4} {3,5} {1,5} {6,8} {5,9} {8,10} 最多能选出的区间数目:3
满足最多能选出的区间如下:
{2,4} {6,8} {8,10}