您的位置:首页 > 其它

贪心算法之活动选择问题

2017-11-05 16:22 281 查看
这一篇开始简单的介绍下贪心算法。在求解最优化问题的过程中,每一步我们都面临着很多选择,当然动态规划是最主要和最有用的算法,但是对于一些问题来说,可以选用更高效的算法,比如贪心算法,贪心算法就是每一步在当时都做出最佳的选择,也就是它总是做出局部最优解,然后寄希望这样的操作能找到全局自由解。

贪心算法不一定能找到全局最优解,但对大多数问题来说能找到最优解。

先来看第一个问题--------活动选择问题

这个例子是一个调度竞争共享资源的多个活动的问题,目标是选出一个最大的互相兼容的活动集合,假设有n个活动,这些活动共用 同一个资源,而这个资源在某一个时刻只能供某一个活动使用,每个活动都会有一个开始时间和结束时间,如果被选中,则发生在这个时间区间里;如果两个活动不重叠,则称它们是兼容的。在活动选择问题中,我们希望选出一个最大活动兼容集,假设活动按照结束时间递增排序



1、我们先考虑动态规划,给出递归式:

c[i,j]=c[i,k]+c[k,j]+1,c[i,j]表示在活动si结束后开始,在活动sj未开始之前结束的最优解,当然这是我们确定sk属于最优解的时候,如果不知道sk是否包含在最优解中时,我们需要逐个考察,即下边的递归式:



有了这个递归式,我们可以设计一个带备忘机制的递归算法,或者自底向上填表法

自底向上填表法:

void Dp(DataType s[],DataType f[],DataType c[N+1][N+1],int point[N+1][N+1])
{
for(int j=1;j<=N;j++)
for(int i=j;i<=N;i++)
c[i][j] = 0;//i>=j时为空集
for(int j=2;j<=N;j++)
{
for(int i=1;i<j;i++)
{
for(int k=i+1;k<j;k++)
{
if(s[k]>=f[i]&&f[k]<=s[j])
{
if((c[i][k]+c[k][j]+1)>c[i][j]){
c[i][j]=c[i][k]+c[k][j]+1;
point[i][j]=k;
}
}
}
}
}
}
void print(int start,int end,int point[N+1][N+1])
{
if(start<end){
print(start,point[start][end],point);
if(point[start][end]!=0)
cout<<"a"<<point[start][end];
}

}


2、贪心选择

考虑这样一种贪心选择方法,选择一个最先结束的活动,然后再从剩下的子问题中选择与其兼容的,如此反复进行,直到没有剩余活动。当然这只是一种贪心选择方法,再设计算法时,一般是自上而下的设计。

1)、递归贪心算法

//递归贪心算法
void Select_TX1(DataType s[],DataType f[],int k,int n,vector<int> &v)
{
int m=k+1;
while(m<=n && s[m]<f[k])
m=m+1;
if(m<=n)
{
v.push_back(m);
Select_TX1(s,f,m,n,v);
}
}


结果保存在vector中,注意形参是vector的引用,应用上述代码时注意,活动是按结束时间递增排序好的。

2)、迭代贪心算法

void Select_TX2(DataType s[],DataType f[],int n,vector<int> &v)
{
int k=1;
v.push_back(k);
for(int i=2;i<=n;++i)
{
if(s[i]>f[k])
{
k=i;
v.push_back(k);
}
}
}


贪心算法的代码很简单,设计贪心算法的难点在于这样去选择一种合适的贪心选择策略,这个问题我们以选择结束时间最早的活动作为贪心策略,当然还有其他方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: