贪心算法(放灯问题、分割金条、IPO(项目获取最大钱数))

一、放灯问题

给定一个字符串str,只由‘X’和‘.’两种字符构成。

‘X’表示墙,不能放灯,也不需要点亮

‘.’表示居民点,可以放灯,需要点亮

如果灯放在i位置,可以让i-1,i和i+1三个位置被点亮

返回如果点亮str中所有需要点亮的位置,至少需要几盏灯。

贪心策略:
分为两种情况

i为当前字符处
第一种情况:当前字符是墙 ’ X ',这种情况下下次决定直接跳到下一个 i+1 字符处。
第二种情况:当前字符是居民点 ’ . ',这种情况下先看下一个字符,如果 i+1 字符是 ‘ X ’,则下次决定直接到 i+2 字符处,如果 i+1 字符是 ’ . ',则下次决定跳到 i+3 字符处。

这样局部的每一步都寻求到最优的决定,最后得到全局最优的决定。
请添加图片描述
代码如下:

 public static int minLight2(String road){
    
    
        char[] str=road.toCharArray();
        int i=0;
        int light=0;
        while (i<str.length) {
    
    
            //当前字符为‘X’,下一次决定到i+1字符处
            if (str[i]=='X') {
    
    
                i=i+1;
            }else {
    
    
                //不管i到i+3中都是什么字符,都要有一盏灯
                light++;
                if (i+1==str.length){
    
    
                    break;
                }
                else {
    
    
                    //如果i+1字符处为‘X’,下次决定直接跳到i+2
                    if (str[i+1]=='X'){
    
    
                        i=i+2;
                     //如果i+1字符处为‘.’,下次决定直接跳到i+3
                    }else{
    
    
                        i=i+3;
                    }
                }
            }
        }
        return light;
    }

二、分割金条

一块金条切成两半,是需要花费和长度数值一样的铜板的。

比如长度为20的金条,不管切成长度多大的两半,都要花费20个铜板。一群人想整分整块金条,怎么分最省铜板?

例如,给定数组{10,20,30},代表一共三个人,整块金条长度为 10+20+30=60. 金条要分成10,20,30三个部分。

如果, 先把长度60的金条分成10和50,花费60 再把长度50的金条分成20和30, 花费50 一共花费110铜板。

但是如果, 先把长度60的金条分成30和30,花费60 再把长度30 金条分成10和20,花费30 一共花费90铜板。

输入一个数组,返回分割的最小代价。(不考虑给定的数组顺序,只要能切出数组中的长度即可)

贪心策略:

  1. 准备一个小根堆,把数组中的数据放入小根堆当中
  2. 从小根堆依次弹出两个数(每次都是弹出小根堆中最小的两个数),相加,再放入小根堆
  3. 依次弹出的数相加生成哈夫曼树,哈夫曼树带权路径的权值之和就是题目中分割的最小代价

哈夫曼树:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述
代码如下:

public static int lessMoney2(int[] arr) {
    
    
		//小根堆
        PriorityQueue<Integer> pQ=new PriorityQueue<>();
        //将数组中数依次加入小根堆
        for (int i=0;i<arr.length;i++) {
    
    
            pQ.add(arr[i]);
        }
        int sum=0;
        int cur=0;
        //弹出相加,放回小根堆
        while (pQ.size()>1) {
    
    
            cur=pQ.poll()+pQ.poll();
            sum+=cur;
            pQ.add(cur);
        }
        return sum;
    }

三、项目获取最大钱数

输入:正数数组costs、正数数组profits、正数K、正数M

给你两个数组,costs[i]和profit[i]是,costs[i]表示每个项目所花费的钱数,profit[i]表示每个项目所能挣得的利润。

k表示你不能并行、只能串行的最多做k个项目

w表示你初始的资金

每个项目只做一次

说明:你每做完一个项目,马上获得的收益,可以支持你去做下 一个 项目。

输出: 你最后获得的最大钱数。

贪心策略:

  1. 准备一个大根堆和一个小根堆,大根堆中根据项目的利润排序,小根堆中根据项目的花费排序。
  2. 将项目放入小根堆中排序
  3. 把小根堆中花费小于等于初始资金的项目放入大根堆中。
  4. 依次弹出大根堆,每次都是弹出大根堆中利润最大的值
    请添加图片描述
    请添加图片描述
    请添加图片描述
	// 最多K个项目
    // W是初始资金
    // Profits[] 利润
    // Capital[] 资金
    // 一定等长
    // 返回最终最大的资金
    public static int findMaximizedCapital(int K, int W, int[] profits, int[] Capital) {
    
    
    	//小根堆
        PriorityQueue<Program> minCostQ = new PriorityQueue<>(new MinCostComparator());
        //大根堆
        PriorityQueue<Program> maxProfitQ = new PriorityQueue<>(new MaxProfitComparator());
        //将项目放入小根堆中
        for (int i = 0; i < profits.length; i++) {
    
    
            minCostQ.add(new Program(profits[i], Capital[i]));
        }
        //只能进行K个项目
        for (int i = 0; i < K; i++) {
    
    
        	//小根堆中花费小于初始资金的项目弹出放入大根堆中
            while (!minCostQ.isEmpty() && minCostQ.peek().c <= W) {
    
    
                maxProfitQ.add(minCostQ.poll());
            }
            if (maxProfitQ.isEmpty()) {
    
    
                return W;
            }
            //利润求和
            W += maxProfitQ.poll().p;
        }
        return W;
    }
	//项目类
    public static class Program {
    
    
        public int p;
        public int c;

        public Program(int p, int c) {
    
    
            this.p = p;
            this.c = c;
        }
    }
	//小根堆比较器,根据项目的花费排序
    public static class MinCostComparator implements Comparator<Program> {
    
    

        @Override
        public int compare(Program o1, Program o2) {
    
    
            return o1.c - o2.c;
        }
    }
	//大根堆比较器,根据项目的利润排序
    public static class MaxProfitComparator implements Comparator<Program> {
    
    

        @Override
        public int compare(Program o1, Program o2) {
    
    
            return o2.p - o1.p;
        }
    }

    public static void main(String[] args) {
    
    
        int[] a = {
    
    0, 1, 1};
        int[] b = {
    
    1, 2, 3};
        System.out.println(findMaximizedCapital(2, 0, b, a));
    }

猜你喜欢

转载自blog.csdn.net/m0_53328239/article/details/130325536