会场安排问题: 假设要用很多个教室对一组活动进行调度。我们希望使用尽可能少的教室来调度所有的活动。请给出一个有效的贪心算法,来确定哪一个活动应使用哪一个教室。
(这个问题也被成为区间图着色(interval-graph coloring)问题。我们可作出一个区间图,其顶点为已知的活动,其边连接着不兼容的活动。为使任两个相邻结点的颜色均不相同,所需的最少颜色对应于找出调度给定的所有活动所需的最少教室数。)
分析:先找出合适的贪心策略,活动按结束时间进行从小到大排序,在保证兼容的情况下,先进入会场的活动结束时间越早越好。依次先从结束时间早的分配会场,没有兼容的会场则开辟新的会场,不要忘记,开辟会场sumRoom+1,每个活动都要遍历所有的会场。使用 贪心策略,只遍历一次所有活动就行。
关键在于:找到合适的贪心策略,因为贪心简化了动规的子问题,但是不是所有的贪心都能得到正确的答案。
/** 贪心算法,解决活动选择问题。。
* 也是一种动规,只是他将不符合条件的子问题都舍弃了
* 这里 活动已经 按结束时间排好序
* @param s:活动的开始时间 采用递归的方法时,要加入一个虚拟活动a0
* @param f:活动的结束时间
* @param k n:活动的规模
*/
public void recursiveActivitySelect(int s[],int f[],int k,int n)
{
int m=k+1;
while(m<=n&&s[m]<f[k])
m++;
if(m<=n)
{
System.out.print("a"+m+" ");
recursiveActivitySelect(s, f, m, n);
}
}
/**
* @param s
* @param f
* 贪心的非递归实现 迭代算法
*/
public void recursiveActivitySelect(int s[],int f[])
{
int n=s.length;
int k=1;
System.out.print("a"+k+" ");
for(int m=2;m<n;m++)
if(s[m]>=f[k])
{
k=m;
System.out.print("a"+m+" ");
}
}
/*按最晚开始时间进行贪心算法,首先参数为一个按照开始时间拍好的序的活动
*开始时间从大到小排序
*/
public void recursiveActivitySelect2(int s[],int f[],int k,int n)
{
int m=k+1;
while(m<=n&&s[k]<f[m])
m++;
if(m<=n)
{
recursiveActivitySelect2(s, f, m, n);
System.out.print("a"+m+" ");
}
}
/** 会场选择问题 :先要对活动按结束时间进行排序 为了使一个将会场能
* 有更大的兼容活动,从而使用较少的会场
* 没有 会场安排下他 ,就开辟新的会场
* @param s
* @param f
* 返回每个会场兼容的情况下,最小使用的会场数,类似于区间图着色问题
* 只是再加入一个集合时,判断是否与集合中的点相邻,
* 会场问题是判断要加入的活动开始时间是否大于会场的最晚结束时间
*/
public int selectRoom(int s[],int f[])
{
int n=s.length;
int time[]=new int [n];
int sumRoom=1;//先开辟一个新的会场 ,把最早结束的活动放进去,开始时的会场总数
time[0]=f[0];//记录会场的最晚结束时间、
for(int i=1;i<n;i++)//遍历所有节点为所有的节点安排会场
{
int flag=0;//此活动刚开始未安排进入会场
for(int j=0;j<sumRoom;j++)
{
if(time[j]<=s[i])
{
flag=1;
time[j]=f[i];//若加入的次会场,更新此会场的最晚结束时间
}
}
if(flag==0)//没有会场装下它,开辟新的会场
{
time[sumRoom]=f[i];//更新时间
sumRoom++;
}
}
return sumRoom;
}</span>
总结:上述两种问题: 先前的排序很重要,最早结束时间,优先选择最早结束时间的活多不能够,使兼容的子序列最多,使用的会场最少。会场安排其实就是