一、部分背包问题
相比较于完全背包问题,部分背包问题在选取物品时,可以只选取物品的部分,而不必须选取整个物品。
那问题就更加简单了,我们以物品的单位重量价值排序,一个物品一个物品的选取即可。
我们将给的道具以单位价值魅力值排序,大者在上,逐个选取。
排序:
//以单位价值魅力进行冒泡排序
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;
}
}