贪心算法

什么是贪心算法

利用贪心策略解决问题往往具有两个重要特征:贪心选择性质和最优子结构

  1. 贪心选择

原问题的整体最优解可以通过一系列的局部最优解得到。

  1. 最优子结构

当一个问题的最优解包含子问题的最优解的时候,称此问题具有最优子结构性质。

具有贪心选择和最优子结构性质就可以只用贪心算法,如何使用呢?
1.贪心策略

贪心策略

2.局部最优解

加勒比海盗船-最优装载问题

/**
 * 伪代码详解:
 * (1)数据结构定义
 * 我们用一维数组存储古董的重量
 * double[] w;
 *
 * (2)对重量进行排序
 * 利用Arrays.sort();
 *
 * (3)按照贪心策略找最优解
 * 首先用ans记录已经装载的古董个数,tmp代表装载到船长的古董的重量,两个变量都初始化为0。然后按照重量大小
 * 有小到大排序,依次检查每个古董,tmp加上该古董的重量,如果小于c,责令ans++;否则,退出。
 * */

package com.chao.greedyAlgorithm;

import java.util.Arrays;

public class GreedyAlgorithm {

    public static int shipLoad(int[] w){
        int C = 30;//船的最大载重
        Arrays.sort(w);
        int ans = 0;
        int tmp = 0;
        for(int i = 0; i < w.length; i++){
            tmp = tmp + w[i];
            if(tmp < C){
                ans++;
            }
        }
        return ans;
    }

    public static void main(String[] args){

        int[] w = {4,1,1,11,3,5,14,1};
        int a = shipLoad(w);
        System.out.println(a);
    }
}

高级重点秘书——会议安排

问题分析

算法设计

伪代码详解

  1. 数据结构定义

一维数组

  1. 对会议结束时间进行递增排序

###算法实现

package com.chao.greedyAlgorithm;

import java.util.ArrayList;
import java.util.List;

public class SecretaryMeeting {

    //s为会议开始时间数组,f为会议结束时间数组,n为会议的总数
    public static List<Integer> GreedyAc(int[] s, int[] f, int n){

        //1、将会议按照结束时间的先后排序
        int[] index = new int[n];//index存储排序后的会议编号
        for(int i = 0; i < n; i++){
            index[i] = i;
        }

        for(int i = 0; i < n-1; i++){//冒泡排序(由小到大),如果n为10,则需要走9趟
            for(int j = 0; j < n-1-i; j++){
                if(f[j] > f[j+1]){
                    int temp = f[j];
                    f[j] = f[j+1];
                    f[j+1] = temp;
                    int a = index[j];
                    index[j] = index[j+1];
                    index[j+1] = a;
                }
            }
        }

        //2、把排好序的会议编号,会议开始时间放到新的数组中
        int newS[] = new int[n];
        for(int i = 0; i < n; i++){
            newS[i] = s[index[i]];
        }

        /*3、开始安排会议 newS[] f[] index[]
        * 贪心策略:
        * 按照会议结束时间非递减的顺序,首先放入第一个会议,将第一个会议的结束时间存入last变量当中。按照顺序检查
        * 下一个会议的开始时间,看时候大于或者等于last,如果是,将其放入,更新last的值,循环,循环的次数就是
        * 会议的个数,每个会议判断一次
        * */
        List<Integer> list = new ArrayList<>();//list存放安排的会议
        int last = f[0];//last存放每次放进去会议的结束时间
        list.add(index[0]+1);
        for(int i = 1; i < n; i++){
            //判断下一个会议的开始时间
            if(newS[i] >= last){
                list.add(index[i]+1);
                last = f[i];
            }
        }
        System.out.println();
        for(int x : list){
            System.out.print(x + " ");
        }
        return list;
    }

    public static void main(String[] args){

        int[] s = new int[]{3,1,5,2,5,3,8,6,8,12};
        int[] f = new int[]{6,4,7,5,9,8,11,10,12,14};
        int n = 10;
        GreedyAc(s,f,n);
    }
}

一场说走就走的旅行——最短路径

package com.chao.greedyAlgorithm;

public class Dijkstra {

    private static int n;//保存顶点个数(城市个数)
    private static int m;//保存边个数
    private static int max = Integer.MAX_VALUE;//用来设定一个比所有权都大的值,用来表示两点之间没有连线
    private static boolean[] flag;//找到一个顶点的最短距离就把他设为true
    private static int[][] map;//保存图中各边的值,两点无边则设为max
    private static int[] dist;//保存源点到其他各点的最短距离
    private static int[] path;//输出路径

    public static void dijkstra(int u){

        //1、初始化源点u到其他各顶点的长度
        for(int i = 1; i <= n; i++){
            dist[i] = map[u][i];
            flag[i] = false;
            if(dist[i] == max){
                path[i] = -1;
            }else{
                path[i] = u;
            }
        }
        dist[u] = 0;
        flag[u] = true;

        //2、找最小,从S-V中找最小的数,加入到S中,如果找不到则跳出循环
        for(int i = 1; i <= n; i++){
            int t = u;//初始化最小数为t=u
            int temp = Integer.MAX_VALUE;//初始化距离为MAX_VALUE
            for(int j = 1; j <=n; j++){//在集合V-S中寻找距离u最近的顶点t
                if(flag[j] == false){
                    if(dist[j] < temp){
                        t = j;
                        temp = dist[j];
                    }
                }
            }
            if(t == u) return;//如果没有找到跳出循环
            flag[t] = true;//如果找到了,将t加入到S中

            //3、更新集合V-S中,与t相邻的的顶点到源点的距离
            for(int j = 1; j <= n; j++){
                if(flag[j] == false && map[t][j] < Integer.MAX_VALUE){//这里"Integer.MAX_VALUE"指的是t到j有边
                    if((dist[t] + map[t][j]) < dist[j]){
                        dist[j] = dist[t] + map[t][j];
                        path[j] = t;
                    }
                }
            }
        }
    }

    public static void main(String[] args){

    }

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值