实验内容:
本实验要求基于算法设计与分析的一般过程(即待求解问题的描述、算法设计、算法描 述、算法正确性证明、算法分析、算法实现与测试),使用贪心法求解会场安排问题,以期 从实践中理解贪心法的思想、求解策略及步骤。有余力者,可以巩固单源最短路径、最小生 成树、哈夫曼编码等基于贪心策略的求解算法的练习。
实验目的:
◆ 理解贪心法的核心思想以及分治法求解过程。
实验步骤:
步骤 1:理解问题,给出问题的描述。
设有 n 个会议的集合 C={1,2,…,n},其中每个会议都要求使用同一个资源(如会议 室),而在同一时间内只能有一个会议使用该资源。每个会议 i 都有要求使用该资源的起始时间 ai 和结束时间 bi,且 ai < bi 。如果选择了会议 i 使用会议室,则它在半开区间[ai, bi)内占用该资源。如果[ai, bi)与[aj , bj)不相交,则称会议 i 与会议 j 是相容的。会场安排问题要 求在所给的会议集合中选出最大的相容活动子集,也即尽可能地选择更多的会议来使用资源。
步骤 2:算法设计,包括算法策略与数据结构的选择;
1.初始化。开始时间存入数组 A;结束时间存入数组 B 中且按照结束时间的非减序排 序,A 相应调整;集合 C 存储解,会议 i 如果在集合 C 中,当且仅当 C[i]=true;
2.根据贪心策略,首令 C[1]=true;
3.依次扫描每一个会议,如果会议 i 的开始时间不小于最后一个选入 C 中的会议的结束 时间,则将会议 i 加入 C 中;否则,放弃,继续检查下一个会议 C 中会议的相容性。
步骤 3:描述算法。希望采用源代码以外的形式,如伪代码、流程图等;
要尽可能多的安排会议,显然采取贪最早结束时间的策略。
设会议 i 的起始时间 ai 和结束时间 bi 的数据类型为整形(限制在整点);
则 GreedySelector 算法描述如下:
Void GreedySelector(int n,int b[ ],int e[ ],bool A[ ])
{ //b 中元素按非递减序排列,a 中对应元素做相应调整;
int I,j;
C[1]=true; //初始化选择会议的集合 C,只包含会议 1;
j=1;i=2; //从第二(i)个会议开始寻找与会议 1(j)相容的会议;
while(i<=n){
if(a[i]>=b[i])
{
C[i]=true;j=I;
}
else
C[i]=false;
}
}
步骤 4:算法的正确性证明。这个环节,在理解的基础上对算法的正确性给予证明;
设集合 D 为最优解集合,其中第一个集合为 k。如果 k=1,则说明该集合是贪心选择得 出的最优解。如果 k>1,令集合 E=(D-{k})U{1}。因为活动 1 的结束时间比活动 k 少,并且 集合 D 是相容的,所以集合 E 也是相容。两个集合的活动个数也是一样多的。因此集合 D 也 是该问题的最优解之一。
步骤 5:算法复杂性分析,包括时间复杂性和空间复杂性;
该算法的时间复杂度为排序的复杂度:O(nlogn),空间复杂度为常数阶:O(1)。
步骤 6:算法实现与测试。附上代码;
#include <iostream>
#include <string>
using namespace std;
int greedySelector(int n,int s[],int f[],bool a[])
{
a[1]=true;
int j=1;
int cot=1;
int q=1;
cout<<"安排后可以进行的会议:"<<endl;
cout<<q<<" "<<s[j]<<" "<<f[j]<<endl;
for(int i=2;i<=n;i++)
{
if(s[i]>=f[j])
{
q+=1;
cout<<q<<" "<<s[i]<<" "<<f[i]<<endl;
a[i]=true;
j=i;
cot++;
}
else
a[i]=false;
}
return cot;
}
int main()
{
int n;
cout<<"会议总数:";
cin>>n;
int s[n],f[n];
bool a[n];
cout<<"输入会议开始和结束时间:"<<endl;
for(int i=1;i<=n;i++)
{
cin>>s[i];
cin>>f[i];
}
int cot;
cot=greedySelector(n,s,f,a);
cout<<"安排会议总数为:"<<cot<<endl;
system("pause");
return 0;
}
实验总结:
贪心算法每个阶段的决策一旦做出就不可更改。不允许回溯。
贪心算法和动态规划本质 上是对子问题树的一种修剪,两种算法要求问题都具有的一个性质就是子问题最优性。动态 规划方法代表了这一类问题的一般解法,我们自底向上构造子问题的解,对每一个子树的 根,求出下面每一个叶子的值,并且以其中的最优值作为自身的值,其它的值舍弃。而贪心 算法是动态规划方法的一个特例,可以证明每一个子树的根的值不取决于下面叶子的值,而 只取决于当前问题的状况。贪心算法的性质是所求问题的整体最优解可通过一系列局部最优 的选择获得。