贪心算法

适用问题

贪心选择:
整体的最优解可通过一系列局部最优解达到。每次的选择可以依赖以前做出的选择,但不能依赖后面的选择。

最优子结构:
问题的整体最优解中包含着他的子问题的最优解。

贪心算法和动态规划的区别

动态规划:
每步所做的选择往往依赖于相关子问题的解。通常以自底向上的方式解各子问题。
贪心算法:
以迭代的方式做出相继的贪心选择,每做一次贪心选择就将所求的问题简化为规模更小的子问题。通常以自顶向下的方式进行。

活动安排问题

问题描述:
有若干个活动,第i个开始时间和结束时间是[Si,fi),只有一个活动场地可以利用,活动之间不能交叠,求最多安排多少个活动?
在这里插入图片描述
思路:
将活动的结束时间由小到大排序,安排时使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。

代码:

public class activitiesArrange {
    public static int greedySelector(int[] s, int[] f, boolean[] a) {
        int n = s.length - 1;
        //安排第一个活动,标记为true
        a[1] = true;
        int j = 1;
        int count = 1;
        for (int i = 2; i <= n; i++) {
        	//检验下一个活动的开始时间是否晚于当前活动的结束时间
            if (s[i] >= f[j]) {
                //如果晚于,则表示两个活动相互兼容,将活动标记为true
                a[i] = true;
                j = i;
                //记已经安排活动的个数
                count++;
            } else {
                //与已安排活动不兼容,标记此活动未安排
                a[i] = false;
            }
        }
        return count;
    }

    public static void main(String[] args) {
        //初始化数据s数组记录活动开始时间;f数组记录活动结束时间(已经提前按照结束时间由小到大排好序)
        int[] s = { 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
        int[] f = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
        //声明一个boolean型数组
        boolean[] a = new boolean[s.length];	//记录是否选择了该活动
        int result = greedySelector(s, f, a);
        System.out.println("Result is: " + result);
        for (int i = 1; i <= s.length - 1; i++) {
            if (a[i]) {
                System.out.println("第" + i + "活动被选中,其开始时间为:" + s[i] + ",结束时间为:" + f[i]);
            }
        }
    }
}

一般背包

与0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包。

问题:

有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

思路:
首先,计算每种物品单位重量的价值Vi/Wi ,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包(若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包)。依此策略一直地进行下去,直到背包装满为止。

代码:

//一般背包问题
import java.util.Arrays;
/**
 * 贪心算法--->背包问题
 * 假设有一个背包最大可以装    150kg 物品
 * 某物品    重量        价值(元)      性价比(单位重量的价格)    
 *   a  35kg     10              10/35
 *   b  30kg     40              40/30
 *   c  60kg     30           30/60
 *   d  50kg     50           50/50
 *   e  40kg     35           35/40
 *   f  10kg     40           40/10
 *   g  25kg     30           30/25
 *   
 * 求:背包可以装入的最大价值?
 */
public class knapsack {
    private static  int capacity=152;	//背包最大容量
    private static int [] goods_weights=new int [] {35,30,60,50,40,10,25};	//各个物品的重量
    private static int [] goods_values=new int[] {10,40,30,50,35,40,30};	//各个物品的价值
    /**
     * @param capacity  背包容量
     * @param weights   各个物品的重量
     * @param values    各个物品的价值
     */
    private void knapsackGreedy(int capacity,int weights[],int values[]) {	
        int n=weights.length;   //物品的数量
        Double[] r=new Double[n];  //保存性价比的数组
        int [] index=new int[n]; //保存按性价比排序的物品的下标
        //计算得到各个物品的性价比
        for (int i = 0; i < n; i++) {
            r[i]=(double)values[i]/weights[i];
            index[i]=i;  //初始化各个物品的默认性价比排序
        }
        
        //对各个物品的性价比进行排序
        for(int i=0;i<r.length-1;i++) {
            for(int j=i+1;j<r.length;j++) {
                if(r[i]<r[j]) {
                    double temp=r[i];
                    r[i]=r[j];
                    r[j]=temp;
                    //将排序后性价比的下标更新为性价比排序后的位置
                    int x=index[i];
                    index[i]=index[j];
                    index[j]=x;
                }
            }
        }
        
        //将排序好的重量和价值分别保存到数组
        int [] w1=new int[n];
        int [] v1=new int[n];
        for(int i=0;i<n;i++) {
            w1[i]=weights[index[i]];
            v1[i]=values[index[i]];
        }
        
        //将物品装入背包
        //记录哪些物品已经被装入背包       0 没有装入背包    1 代表已经装入背包
        int [] x=new int[n];  
        double maxValue=0;
        for(int i=0;i<n;i++) {
            if(w1[i]<=capacity) {
                //还可以装的下
                x[i]=1;  //表示将该物品装入背包
                System.out.println("物品:"+w1[i]+" 被放进了");
                maxValue+=v1[i];
                capacity-=w1[i];
            }else{
            	System.out.println("物品:"+w1[i]+" 被放进了一部分");
            	x[i]=2;  //表示将该物品的一部分装入背包
            	maxValue = (double)capacity+r[i]*(double)capacity;
            	break;
            }
        }
        System.out.println("总共放下的物品的数量为:"+Arrays.toString(x));
        System.out.println("最大价值为:"+maxValue);
    }
    
    public static void main(String[] args) {
    	knapsack k=new knapsack();
        k.knapsackGreedy(capacity, goods_weights,
                goods_values);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值