硬币问题![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/af911d93321eb87a871d44238a057512.png)
首先10的9次方这个要注意,不可能用暴力解法
优先使用面值大的硬币
搜索算法和动态规划算法是在多种策略中选取最优解
而贪心算法则不同,它是遵循某种规则,不断地选取当前最优策略。例如在本题中“优先使用面值最大的硬币”就是在计算过程中所遵循的规则。并且,我们只考虑“尽可能多的使用面值大的硬币”这一种当前最优策略
这里的硬币问题也相当与一种背包问题,那么比起用下节要介绍的动态规划算法求解,贪心算法更简单更高效
package 程序设计竞赛;
import java.util.Scanner;
public class 贪心¥硬币问题 {
//硬币的面值
final static long[] V=new long[]{1,5,10,50,100,500};
//long是基本类型,Long是对象类型
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
long[] number=new long[6];
for(int i=0;i<6;i++){
number[i]=sc.nextLong();
}
long A=sc.nextLong();
//贪心问题
int ans=0;
for(int i=5;i>=0;i--){
//使用硬币的枚数
long t=Math.min((A/V[i]), number[i]);
A-=t*V[i];
ans+=t;//用了几个硬币
}
System.out.println(ans);
}
}
区间问题
题目这个是要进行画图看的才清楚。
在可选的工作(也就是和目前已选的工作都不重叠的工作中)每次都选取开始时间最早的工作
因此,如果我们不慎重地选择了一个正确的规则,就会得到错误的算法。
HashMap和TreeMap
package 程序设计竞赛;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
public class 贪心¥区间问题 {
//final static int Max_n=100000;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
long [] s=new long[n];
long [] t=new long[n];
for(int i=0;i<n;i++){
s[i]=sc.nextLong();
}
for(int i=0;i<n;i++){
t[i]=sc.nextLong();
}
//用于对工作排序的键值对,(书上写的是pair)
Map<Long,Long> map=new TreeMap<>();
//贪心
//为了然后接受时间早的工作排在前面,把T存入first,把S存入second
for(int i=0;i<n;i++){
map.put(t[i], s[i]);
}
//t是最后所选工作的结束时间
int ans=0;long m=0;
for(int i=0;i<n;i++){
if(m<map.get(t[i])){
ans++;
m=t[i];
}
}
System.out.println(ans);
}
}
字典序最小问题
字典序比较类的问题经常能用到上贪心法
package 程序设计竞赛;
import java.util.Scanner;
public class 贪心¥字典序最小问题 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
String s=sc.next();
//s[a],s[a+1]``
char[] ss=s.toCharArray();
int a=0;
int b=n-1;
while(a<=b){
//将从左起和右起的字符串比较
boolean left=false;
//for(int i=0;a+i<=b;i++){
//当左边的字符串小于右边的时候
if(ss[a]<ss[b]){
left=true;
//break;
}else if(ss[a]>=ss[b]){
left=false;
//break;
}
//}
if(left)
System.out.print(ss[a++]);
else{
System.out.print(ss[b--]);
}
}
}
}
Saruman’s Army
package 程序设计竞赛;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class 贪心¥SarumanArmy {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int r=sc.nextInt();
int[] x=new int[n];
//Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<n;i++){
x[i]=sc.nextInt();
}
//要先排序
Arrays.sort(x);
int i=0,ans=0;
while(i<n){
//s是没有被覆盖的最左边的位置
//int s=x[i];
//i++;
//上面两句可以合为
//System.out.println("i0="+i);
int s=x[i++];
//System.out.println("si="+i);
//System.out.println("s="+s);
//一直向右前进直到距s的距离大于r的点
while(i<n&&x[i]<=s+r)
i++;
//System.out.println("i="+i);
//p位新加上标记的位置
int p=x[i-1];//这个点是要标记的
//一直享有前进知道距p的距离大于r的点
while(i<n&&x[i]<=p+r)
i++;
//System.out.println("i1="+i);
ans++;
//两个一循环
}
System.out.println(ans);
}
}
Fence Repair
对于最优解来讲,最短的板应当是深度最大的叶子节点之一。所以与这个叶子节点同一深度的兄弟节点一定存在,并且由于同样是最深的叶子节点,所以应该对应于次短的板
输入点生成树
package 程序设计竞赛;
import java.util.Arrays;
import java.util.Scanner;
public class FenceRepair {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] len=new int[n];
for(int i=0;i<n;i++){
len[i]=sc.nextInt();
}
long ans=0;
//将两块板平和
//这个不能直接排序,因为这个如果有重复元素构成二叉树不可以
while(n>1){
int mill1=0,mill2=1;
if(len[mill1]>len[mill2])
swap(mill1,mill2);
for(int i=2;i<n;i++){
if(len[i]<len[mill1]){
mill2=mill1;
mill1=i;
}else if(len[i]<len[mill2]){
mill2=i;
}
}
//将两块板拼合
int t=len[mill1]+len[mill2];
ans+=t;
len[mill1]=t;
len[mill2]=len[n-1];
n--;
}
}
private static void swap(int mill1, int mill2) {
// TODO Auto-generated method stub
int t=mill1;
mill1=mill2;
mill2=t;
}
}