一、问题描述:
设有n 个顾客同时等待一项服务。顾客i需要的服务时间为ti, 1≦i ≦n 。共有s处可以提供此服务。应如何安排n个顾客的服务次序才能使平均等待时间达到最小?平均等待时间是n 个顾客等待服务时间的总和除以n。
二、贪心选择策略
假设原问题为T,而我们已经知道了某个最优服务系列,即最优解为A={t(1),t(2),….t(n)}(其中t(i)为第i个用户需要的服务时间),则每个用户等待时间为:
T(1)=t(1);T(2)=t(1)+t(2);...T(n):t(1)+t(2)+t(3)+……t(n);
那么总等待时问,即最优值为:
TA=n*t(1)+(n-1)*t(2)+…+(n+1-j)*t(i)+…2*t(n-1)+t(n);
由于平均等待时间是n个顾客等待时间的总和除以n,故本题实际上就是求使顾客等待时间的总和最小的服务次序。
本问题采用贪心算法求解,贪心策略如下:对服务时间最短的顾客先服务的贪心选择策略。首先对需要服务时间最短的顾客进行服务,即做完第一次选择后,原问题T变成了需对n-1个顾客服务的新问题T’。新问题和原问题相同,只是问题规模由n减小为n-1。基于此种选择策略,对新问题T’,选择n-1顾客中选择服务时间最短的先进行服务,如此进行下去,直至所有服务都完成为止 。
三、问题的贪心选择性质
先来证明该问题具有贪心选择性质,即最优服务A中t(1)满足条件:t(1)<=t(i)(2<i<n)。
用反证法来证明:假设t(1)不是最小的,不妨设t(1)>t(i)(i>1)。
设另一服务序列B=(t(i),t(2),…,t(1)…,t(n))
那么TA-TB=n*[t(1)-t(i)]+(n+1-i)[t(i)-t(1)]=(1-i)*[t(i)-t(1)]>0
即TA>TB,这与A是最优服务相矛盾。
故最优服务次序问题满足贪心选择性质。
四、问题的最优子结构性质
在进行了贪心选择后,原问题T就变成了如何安排剩余的n-1个顾客的服务次序的问题T’,是原问题的子问题。
若A是原问题T的最优解,则A’={t(2),…t(i)…t(n))是服务次序问题子问题T’的最优解。
证明:假设A’不是子问题T’的最优解,其子问题的最优解为B’,则有TB’<TA’,而根据TA的定义知,TA’十t(1)=TA。因此TB’+t(1)<TA’+t(1)=TA,即存在一个比最优值TA更短的总等待时间,而这与TA为问题T的最优值相矛盾。因此,A’是子问题T’的最优值。
从以上贪心选择及最优子结构性质的证明,可知对最优服务次序问题用贪心算法可求得最优解。
根据以上证明,最优服务次序问题可以用最短服务时间优先的贪心选择可以达到最优解。故只需对所有服务先按服务时间从小到大进行排序,然后按照排序结果依次进行服务即可。平均等待时间即为TA/n。
五、算法实现
由多处最优服务次序问题具有贪心选择性质和最优子结构性质,容易证明算法greedy的正确性。本算法采用最短服务时间优先的贪心策略。首先将每个顾客所需要的服务时间从小到大排序。然后申请2个数组:st[]是服务数组,st[j]为第j个队列上的某一个顾客的等待时间;su[]是求和数组,su[j]的值为第j个队列上所有顾客的等待时间;
double greedy(vector<int>x,int s)
{
vector<int>st(s+1,0)
vector<int>su(s+1,0)
int n=x.size()
sort(x.begin(),x.end())
int i=0,j=0
while(i<n){
st[j]+=x[i]
su[j]+=st[j]
i++
j++
if(j==s)j=0//循环分配顾客到每一个服务点上
}
double t=0
for(i=0i<si++) t+=su[i]
t/=n
return t
}
六、算法测试结果
七、算法复杂性分析
程序主要是花费在对各顾客所需服务时间的排序和贪心算法,即计算平均服务时间上面。其中,贪心算法部分只有一重循环影响时间复杂度,其时间复杂度为O(n):而排序算法的时间复杂度为O(nlogn)。因此,综合来看算法的时间复杂度为O(nlogn)。
八、参考文献
[1] 王晓东.计算机算法设计与分析(第3版)[M].北京:电子工业出版社,2007.
[2] 陈媛.《算法与数据结构》[M],清华大学出版社, 第1版,2005.4.
[3] 王晓东.算法设计与实验题解 [M].北京:电子工业出版社,2008.
附录(程序代码)
#include<iostream>
#include <vector>
#include<algorithm>
using namespace std
using std::vector
double greedy(vector<int>x,int s)
{
vector<int>st(s+1,0)
vector<int>su(s+1,0)
int n=x.size()
sort(x.begin(),x.end())
int i=0,j=0
while(i<n){
st[j]+=x[i]
su[j]+=st[j]
i++
j++
if(j==s)j=0
}
double t=0
for(i=0i<si++) t+=su[i]
t/=n
return t
}
void main()
{int n//等待服务的顾客人数
int s//服务点的个数
int i
int a
int t//平均服务时间
vector<int>x
cout<<"please input the num of the customer:"<<endl
cin>>n
cout<<"please input the num of the server:"<<endl
cin>>s
cout<<"please input the need service time of each customer:"<<endl
for(i=1i<=ni++){
cout<<"No."<<i<<endl
cin>>a
x.push_back(a)
}
t=greedy(x, s)
cout<<"the least average waiting time is:"<<t<<endl
}
这个题目很有意思,首先,原来一共有n个服务,要求最短的平均等待时间,由于每个服务所需要的时间是一定的,这就是说,
只要满足在最短的时间内完成所有的服务就行了。
在 *** 作系统之中,进程的分配有一种分配方式称为SJF(短作业优先法),这个方法可以得到最短的平均等待时间。
你的这个题目就好比是进程的分配,要求得最短的平均等待时间,只要优先执行需要时间较少的服务即可。
按照这个思路,你只需要对输入的n个服务时间进行排序(从小到大),然后依次执行,即是最短等待时间序列。
如你的例子,执行顺行为:1 12 33 55 56 99 99 234 812 1000
所需要的等待时间依次为:0 1 13 56 101 157 256 355 589 1401
故最短的平均等待时间是:292.9(但愿我没有算错)
不知道你的答案是怎么来的。
程序就不写了,没什么意义。
程序运行有他们各自的优先次序,所有程序都要占用处理器资源,处理器处理任务有一个先后次序,一般的计算机中有31个优先等级,系统的内核占据了最高的一些等级,这样就能保证系统的`稳定,而普通的应用程序一般在比较后面的等级。在普通应用程序中间也有优先次序,他们本来在处理器面前是人人平等的,但还是有些细微的差别,前台的程序(当前正在使用)的优先级要比后台的程序高。
你可以自己调节应用程序的优先级:
打开任务管理器,点到“进程”选项卡,选一个应用程序的进程,点击右键,会d出一个快捷菜单,选择“设置优先级”,这里有6个等级:实时,高,高与标准,标准,低于标准,低。你可以让你的程序强行调度到更高或更低(自然为别的程序腾出了资源)的等级。如果你不知道某个应用程序的具体进程,可以如下 *** 作:点到“应用程序”选项卡,右键点中一个任务,选择“转到进程”,就会转到该程序的进程,这样你就找到了该程序的进程了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)