贪心算法-活动安排问题
活动安排问题是可以用贪心算法有效求解的很好的例子。
问题:有n个活动的集合A={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。
求解:安排尽量多项活动在该场地进行,即求A的最大相容子集。
设待安排的11个活动的开始时间和结束时间按结束时间的升序排列如下:
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
s[i] | 1 | 3 | 0 | 5 | 3 | 5 | 6 | 8 | 8 | 2 | 12 |
f[i] | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
将此表数据作为实现该算法的测试数据。
【算法分析】
分析:每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si <fi 。如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si≥fj或sj≥fi时,活动i与活动j相容。
例:给出待安排的11个活动的开始时间和结束时间,要求安排尽量多项活动使用会场。
首先,任意输入这11个活动。
然后对活动以其完成时间的非减序排列。(意义:使剩余的可安排时间段极大化,以便安排尽可能多的相容活动。)
将第一次活动结束时间f[1]与后面活动开始时间s[2]相比较,若s[2]<f[1]则继续比较,直到s[4]>f[1],选中此活动。再用活动4的结束时间f[4]与其后活动的开始时间比较……同理类推,直到比较完成为止,最后选出合条件的活动1,活动4,活动8和活动11,它们将依次被安排使用该场地。
具体代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
/*
测试数据我把它倒过来了,方便测试代码的排序和活动id的正确
11
12 14
2 13
8 12
8 11
6 10
5 9
3 8
5 7
0 6
3 5
1 4
*/
public class 贪心算法 {
/*
方法一。运用数组来排序和实现,算法时间复杂度高。
static int n;
static int[] s;
static int[] f;
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
n=input.nextInt();
s=new int[n];
f=new int[n];
for(int i=0;i<n;i++) {
s[i]=input.nextInt();
f[i]=input.nextInt();
}
for(int i=0;i<n;i++) {
for(int j=i;j<n;j++) {
if(f[j]<f[i]) {
{int temp=f[j];f[j]=f[i];f[i]=temp;}
{int temp=s[j];s[j]=s[i];s[i]=temp;}
}
}
}
int[] x=new int[n];
x[0]=1;
int j=f[0];
for(int i=0;i<n;i++) {
if(s[i]>j) {
j=f[i];
x[i]=1;
}
}
for(int i=0;i<n;i++) {
if(x[i]==1) {
System.out.print(i+1+" ");
}
}
}*/
/*我创建了一个类来体现活动的标号(id)和开始时间(s),结束时间(f)
*运用Comparable接口重写了 compareTo()方法
*然后吧Node储存在集合里,然后利用Collections进行sort排序,把Node进行整体排序
*/
static class Node implements Comparable<Node>{
int id;
int s;
int f;
@Override
public int compareTo(Node o) {
Integer a=this.f;
Integer b=o.f;
return a.compareTo(b);
}
@Override
public String toString() {
return "Node [id=" + id + ", s=" + s + ", f=" + f + "]";
}
}
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
List<Node> list=new ArrayList<Node>();
for(int i=0;i<n;i++) {
Node node=new Node();
node.id=i+1;
node.s=input.nextInt();
node.f=input.nextInt();
list.add(node);
}
Collections.sort(list);
Node node1=list.get(0);
int j=node1.f;
System.out.print(node1.id);
for(Node nd:list) {
if(nd.s>j) {
j=nd.f;
System.out.print(" "+nd.id);
}
}
}
}
后面的方法应该比较优化了,用快排的效率肯定比冒泡快很多=。=,把时间复杂度降到O(n)