贪心算法-部分背包问题、活动安排、最优装载问题


一、部分背包问题

在这里插入图片描述

  1. 相比较于完全背包问题,部分背包问题在选取物品时,可以只选取物品的部分,而不必须选取整个物品。
  2. 那问题就更加简单了,我们以物品的单位重量价值排序,一个物品一个物品的选取即可。

在这里插入图片描述

  • 我们将给的道具以单位价值魅力值排序,大者在上,逐个选取。

排序:

//以单位价值魅力进行冒泡排序
for (int i = 1; i <n; i++) {//排序
				Main2 temp = null;
				for (int j = 0; j <n-i; j++) {
					if((main[j].propUnitValue<main[j+1].propUnitValue)) {
						temp = main[j];
						main[j] = main[j+1];
						main[j+1] = temp;
					}
				}
					
			}

选取:
因为我们已经排好序了,我们从上至下的选取物品即可。要关心的问题是物品的数量,和我们还剩多少钱。下面我是针对每个物品一个一个来买,其实可一个物品一个物品来买。

			int glamourTot=0;
			for (int i = 0; i < n; i++) {//选取
				while(main[i].propNum!=0&&main[i].propPrice<=p) {
					glamourTot+=main[i].propGlamour;
					main[i].propNum--;
					p-=main[i].propPrice;
				}
				
			}
			System.out.println(glamourTot);

因为我用的是冒泡排序,时间复杂度为O(n2)。如果使用的是Arrays.sort其时间复杂度为O(n*logn)。

二、活动安排

在这里插入图片描述
有三种排序策略:

  • 以开始时间为准,开始时间早的,排在前面。开始时间早的其结束时间相对早,可给后面流出更多时间
  • 以占用时间为准,占用时间少的,排在前面。这样给其他部门留出更多时间。
  • 以结束时间为准,结束时间造的,排在前面。

三种策略到底那一种更合理呢?第一种,开始时间早的,咱不能确定开始时间早的结束时间一定早。第二种,占用时间少的,可能它的前后有很多空闲时间没有利用起来。相比较而言第三种更合理,以结束时间为准,结束了便是结束了,没有过多的变数。

排序:

for (int i = 1; i <=n-1; i++) {//排序
				actArrange ag = null;
				for (int j = 1; j <=n-i; j++) {
					if(actarrange[j].endTime>actarrange[j+1].endTime) {
						ag = actarrange[j];
						actarrange[j] = actarrange[j+1];
						actarrange[j+1] = ag;
					}
					
				}
				
			}

选取:

输出都可以删除,那样代码更so easy看懂。

System.out.println("如下安排场次最多:");
			int j=1,total=0;//
			for (int i = 2; i <=n; i++) {
				if(actarrange[j].endTime<=actarrange[i].beginTime) {
					actarrange[j].selected = true;
					System.out.println("第"+(total+1)+"个活动开始结束时间:"+"\t"+actarrange[j].actID+"\t"+
				actarrange[j].beginTime+"\t"+actarrange[j].endTime);
					total++;
					j=i;
				}
				
			}
			actarrange[j].selected = true;
			System.out.println("第"+(total+1)+"个活动开始结束时间:"+"\t"+actarrange[j].actID+"\t"+
					actarrange[j].beginTime+"\t"+actarrange[j].endTime);

结果:
在这里插入图片描述

三、最优装载问题

在这里插入图片描述
思路:采用重量最轻者先装的贪心选择策略,可产生最优装载问题的最优解。

排序(快速):

		q(optload,1,n);//排序

private static void q(optLoad[] optload, int l, int r) {
		if(l<r) {
			int s = p(optload,l,r);
			q(optload,l,s-1);
			q(optload,s+1,r);
		}
		
	}
private static int p(optLoad[] optload, int l, int r) {
		int x = optload[l].weight;
		
		int i = l;
		int j = r+1;
		
		while(true) {
			while(optload[++i].weight<x&&i<r);
			while(optload[--j].weight>x);
			
			if(i>=j)
				break;
			swap(optload,i,j);
		}
		optLoad ol = optload[l];
		optload[l] = optload[j];
		optload[j] = ol;
		return j;
	}

	private static void swap(optLoad[] optload, int i, int j) {
		optLoad ol = optload[i];
		optload[i] = optload[j];
		optload[j] = ol;
		
	}

选择(删除syso再看, so easy):

		System.out.println("被选的集装箱的index:"+"\t");
		for (int i = 1; i <=n; i++) {
				if(opt+optload[i].weight<=w) {
					opt+=optload[i].weight;
					optload[i].selected=true;
					System.out.print(optload[i].index+"\t");
				}
				
			}
			System.out.println();
			System.out.println("被选的各集装箱的重量:"+"\t");
			for (int i = 1; i <=n; i++) {
				if(optload[i].selected==true) {
					System.out.print(optload[i].weight+"\t");
				}
				
			}
			System.out.println();
			System.out.println("被选的各集装箱的总重量:"+opt);

结果:
在这里插入图片描述

四、总结

三个有关贪心算法的实例,我们发现都要经过排序再选取这两步。
在这里插入图片描述

1、部分背包代码

import java.util.Scanner;

public class Main2 {	
	private  int propNum;
	private int propPrice;
	private int propGlamour;
	private double propUnitValue;
	
	public Main2(int propNum, int propPrice, int propGlamour, double propUnitValue) {
		super();
		this.propNum = propNum;
		this.propPrice = propPrice;
		this.propGlamour = propGlamour;
		this.propUnitValue = propUnitValue;
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			int n = sc.nextInt();
			int p = sc.nextInt();
			Main2[] main  = new Main2[n];			
			for (int i = 0; i < n; i++) {
				int propNum  = sc.nextInt();
				int propPrice  =sc.nextInt();
				int propGlamour = sc.nextInt();
				double propUnitValue = propGlamour*1.0/propPrice;
				main[i]  =new Main2(propNum,propPrice,propGlamour,propUnitValue);
				
			}
			for (int i = 1; i <n; i++) {//排序
				Main2 temp = null;
				for (int j = 0; j <n-i; j++) {
					
					if((main[j].propUnitValue<main[j+1].propUnitValue)) {
						temp = main[j];
						main[j] = main[j+1];
						main[j+1] = temp;
					}
				}
					
			}
			int glamourTot=0;
			for (int i = 0; i < n; i++) {//选取
				while(main[i].propNum!=0&&main[i].propPrice<=p) {
					glamourTot+=main[i].propGlamour;
					main[i].propNum--;
					p-=main[i].propPrice;
				}
			}
			System.out.println("最大魅力值:");
			System.out.println(glamourTot);
		}		
	}
}

2、活动安排代码

import java.util.Scanner;

public class actArrange {
	private String actID;
	private int beginTime;
	private int endTime;
	private boolean selected;
	
	public actArrange(String actID,int beginTime, int endTime,boolean selected) {
		super();
		this.actID = actID;
		this.beginTime = beginTime;
		this.endTime = endTime;
		this.selected = selected;
	}


	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("输入活动场次:");
		while(sc.hasNext()) {
			
			int n = sc.nextInt();
			actArrange[] actarrange = new actArrange[n+1];
			
			for (int i = 1; i <=n; i++) {
				System.out.println("第"+i+"场的班级和开始结束时间,空格隔开:");
				String actID=sc.next();
				int beginTime = sc.nextInt();
				int endTime = sc.nextInt();
				actarrange[i] = new actArrange(actID,beginTime,endTime,false);
			}
			
			for (int i = 1; i <=n-1; i++) {//排序
				actArrange ag = null;
				for (int j = 1; j <=n-i; j++) {
					if(actarrange[j].endTime>actarrange[j+1].endTime) {
						ag = actarrange[j];
						actarrange[j] = actarrange[j+1];
						actarrange[j+1] = ag;
					}
					
				}
				
			}
			System.out.println("如下安排场次最多:");
			int j=1,total=0;//
			for (int i = 2; i <=n; i++) {
				if(actarrange[j].endTime<=actarrange[i].beginTime) {
					actarrange[j].selected = true;
					System.out.println("第"+(total+1)+"个活动开始结束时间:"+"\t"+actarrange[j].actID+"\t"+
				actarrange[j].beginTime+"\t"+actarrange[j].endTime);
					total++;
					j=i;
				}
				
			}
			actarrange[j].selected = true;
			System.out.println("第"+(total+1)+"个活动开始结束时间:"+"\t"+actarrange[j].actID+"\t"+
					actarrange[j].beginTime+"\t"+actarrange[j].endTime);
		}

	}

}

3、最优装载问题代码

import java.util.Scanner;

public class optLoad {
	private int weight;
	private int index;
	private boolean selected;
	public optLoad(int index,int weight,boolean selected) {
		super();
		this.weight = weight;
		this.index = index;
		this.selected = selected;
	}

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		System.out.println("集装箱的个数:");
		while(sc.hasNext()) {		
			int n = sc.nextInt();
			optLoad[] optload = new optLoad[n+1];	
			System.out.println("各集装箱的重量:");
			for (int i = 1; i <=n; i++) {
				int a = sc.nextInt();
				optload[i] = new optLoad(i,a,false);				
			}
			System.out.println("船的最大载重量:");
			int w =sc.nextInt();			
			q(optload,1,n);//排序
			int opt=0;
			System.out.println("被选的集装箱的index:"+"\t");
			for (int i = 1; i <=n; i++) {
				if(opt+optload[i].weight<=w) {
					opt+=optload[i].weight;
					optload[i].selected=true;
					System.out.print(optload[i].index+"\t");
				}
				
			}
			System.out.println();
			System.out.println("被选的各集装箱的重量:"+"\t");
			for (int i = 1; i <=n; i++) {
				if(optload[i].selected==true) {
					System.out.print(optload[i].weight+"\t");
				}
				
			}
			System.out.println();
			System.out.println("被选的各集装箱的总重量:"+opt);		
		}

	}

	private static void q(optLoad[] optload, int l, int r) {
		if(l<r) {
			int s = p(optload,l,r);
			q(optload,l,s-1);
			q(optload,s+1,r);
		}
		
	}

	private static int p(optLoad[] optload, int l, int r) {
		int x = optload[l].weight;
		int i = l;
		int j = r+1;
		
		while(true) {
			while(optload[++i].weight<x&&i<r);
			while(optload[--j].weight>x);
			
			if(i>=j)
				break;
			swap(optload,i,j);
		}
		optLoad ol = optload[l];
		optload[l] = optload[j];
		optload[j] = ol;
		return j;
	}

	private static void swap(optLoad[] optload, int i, int j) {
		optLoad ol = optload[i];
		optload[i] = optload[j];
		optload[j] = ol;
		
	}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值