这次得发点干货了^_^
贪心算法的实际应用解决:背包问题、线段覆盖问题
1.背包问题:
有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
物品 A B C D E F G
重量 35 30 60 50 40 10 25
价值 10 40 30 50 35 40 30
实现代码( Java ):
package com.kiddingboy_wjj.home;
import java.util.Scanner;
/** * 背包问题 * @author kiddingboy_wjj * */
public class Bage {
private static float[] V;
public static void main(String args[]) {
int wu_num = 0;
float bg_content = 0;
float now_content = 0;
System.out.println("请输入背包容量:");
bg_content = Integer.parseInt(new Scanner(System.in).next());
System.out.println("请输入物品个数:");
wu_num = Integer.parseInt(new Scanner(System.in).next());
int[] W = new int[wu_num];
V = new float[wu_num];
for (int i = 0; i < wu_num; i++) {
System.out.println("请输入第个物品的重量/价值:" + (i + 1));
W[i] = Integer.parseInt(new Scanner(System.in).next());
V[i] = Integer.parseInt(new Scanner(System.in).next());
}
float[] Q = new float[wu_num];
for (int i = 0; i < wu_num; i++) {
Q[i] = V[i] / W[i];
}
// 排序
Q = sort(Q);
int k = 0;
for (k = 0; k < wu_num; k++) {
if (now_content > bg_content)
break;
now_content += V[k];
}
// now_content -= V[k - 1];
System.out.println("当前最大利益是:" + now_content);
}
/** * 执行排序的功能 * * @param Q1 * @return */
private static float[] sort(float[] Q1) {
float temp, temp2;
float[] Q = Q1;
for (int i = 0; i < Q.length - 1; i++)
for (int j = 0; j < Q.length - 1 - i; j++) {
if (Q[j] < Q[j + 1]) {
temp = Q[j];
Q[j] = Q[j + 1];
Q[j + 1] = temp;
temp2 = V[j];
V[j] = V[j + 1];
V[j + 1] = temp2;
}
}
return Q;
}
}
2、线段覆盖问题
1.线段覆盖(lines cover)
题目大意:
在一维空间中告诉你N条线段的起始坐标与终止坐标,要求求出这些线段一共覆盖了多大的长度。
解题思路:
将线段按其坐标进行排序(排序的具体方法:按起始坐标排,起始坐标相同的按终止坐标排,都是小在前大在后),使之依次递增,并按顺序分别编号为X(i),X(i).a代表其起始坐标,X(i).b代表其终止坐标。
然后按排好的顺序依次处理:定义一个变量last记录考虑到当前线段之时被线段覆盖的最大的坐标值,再定义一个变量length记录当前线段覆盖的长度。对于后面的线段,我们把它看成由两个部分组成,即把它分成last之前的线段和last之后的线段。(如果线段全部处在last之后,其last之前的部分不存在。)由于我们排过序,我们可以肯定当前考虑的线段X(i)其处在last之前的部分不会对length造成影响(因为X(i-1).b=last,X(i).a>=X(i-1).a,即X(i)在last之前的部分所处位置肯定被线段X(i-1)覆盖过),所以会对length产生影响的即是X(i)处在last之后的部分。
所以我们可以依次对每条线段做如下处理:(初始化length为零,last为负无穷)
length+=X(i).b-last (X(i).a<=last 且 X(i).b>=last)
length+=X(i).b-X(i).a (X(i).a>last)
last=X(i).b;
最后length就为我们所需要的答案。
实现代码( Java ):
package com.kiddingboy_wjj.home;
import java.util.Scanner;
/** * 线段覆盖问题 * @author kiddingboy_wjj * */
public class Line {
public static void main(String[] args) {
int n, length = 0, last;// length是当前总长度,last是当前总长度的末尾坐标
// Demo *d = new Demo;
System.out.println("输入线段数:");
n = Integer.parseInt(new Scanner(System.in).next());
float[] s_x = new float[n];// 线段起点坐标
float[] e_x = new float[n];// 线段终点坐标
for (int i = 0; i < n; i++) {
System.out.println("请输入第" + (i + 1) + "条线段的起点及终点:");
s_x[i] = Integer.parseInt(new Scanner(System.in).next());
e_x[i] = Integer.parseInt(new Scanner(System.in).next());
}
sort(s_x, e_x, n);// 按递增排序
length = (int) getLength(s_x, e_x, n);
System.out.println("一共覆盖的长度为:" + length);
}
/** * 排序 * * @param s_x * @param e_x * @param n */
static void sort(float s_x[], float e_x[], int n) {
float temp;
// float temp_s[] = new float[n];
// float temp_e[] = new float[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (s_x[i] > s_x[j]) {// 起点大于后者则直接对换
temp = s_x[i];
s_x[i] = s_x[j];
s_x[j] = temp;
temp = e_x[i];
e_x[i] = e_x[j];
e_x[j] = temp;
}
if (s_x[i] == s_x[j]) {// 起点相同,判断终点
if (e_x[i] > e_x[j]) {
temp = s_x[i];
s_x[i] = s_x[j];
s_x[j] = temp;
temp = e_x[i];
e_x[i] = e_x[j];
e_x[j] = temp;
}
}
}
}
}
static float getLength(float s_x[], float e_x[], int n) {
float length = 0, last = e_x[0];
length = e_x[0] - s_x[0];
for (int i = 0; i < n; i++) {
if (s_x[i] >= last) {// 起点大于last则直接加上线段长
length += (e_x[i] - s_x[i]);
} else if (e_x[i] > last) {// 起点小于last,终点大于last,加上多出部分
length += (e_x[i] - last);
}
}
return length;
}
}