实验题目:用贪心算法解决作业调度问题。
实验目的:
1. 学习带时限的作业调度—最大时限选择方法。
2. 掌握贪心算法的应用。
问题描述:
给定任务序列J1J2 ...Jn,假定只有一台处理机为这批作业服务。每件任务Ji给定一个时限di和对应利润Pi。只有在规定时限之内完成作业,才会得到利润Pi。通过设计合适的算法选择和安排任务子集Ji,使得J中的每个作业都能在各自的时限内完工,且使获得的利润∑Pi总和最大。
令d=max{di} 1≤i≤n,b=min{n,d}
任何最大利润的可完工子序列中的作业个数必不大于b。
解答方法:
1. 将任务按时限划分集合,时限按从大到小排列
令d=max{di} 1≤i≤n
2. 在时限为d的作业中选择一个利润最大的作业加入J
3. 在时限不小于d-1的作业中选择一个利润最大的作业加入J
4. 在时限不小于d-2的作业中选择一个利润最大的作业加入J
5. 如此进行下去,直到在时限不小于1的作业中选择利润最大的作业加入J。
预计输入输出
要求:依次输入任务序列J1J2 ...Jn各自对应时限di和对应利润Pi,要求输出最佳作业执行序列,使得获得的利润总和∑Pi最大,并输出最大利润总和。
按下表输入任务序列的参数:
任务Ji |
J1 |
J2 |
J3 |
J4 |
J5 |
J6 |
J7 |
时限di |
2 |
2 |
1 |
3 |
3 |
4 |
4 |
利润Pi |
20 |
15 |
20 |
5 |
1 |
10 |
20 |
预计输出:
作业执行序列为: J3→J1→J6→J7
最大利润为:70
不过这个算法对于N为10^5是超时的,TLE代码:
#include
#include
using namespace std ;
const int maxn=100005;
int p[maxn],d[maxn];
int rank[maxn],vis[maxn];
bool cmp (int a,int b)
{
return p[a]>p[b];
}
int main ()
{
int n,i,j;
while (~scanf("%d",&n))
{
int sum=0,maxd=0;
memset (vis , 0 , sizeof(vis));
for (i=0 ; imaxd)maxd=d[i];
}
sort(rank,rank+n,cmp);
int m=n;
for (i=maxd ; i>0 ; --i)
{
for (j=0 ; j=i)
{
sum+=p[rank[j]];
vis[rank[j]]=1;
//printf("%d\t",j);
break;
}
}
}
printf("%d\n",sum);
}
return 0;
}
看了孔牛博客里的一个类似题目,利用了并查集,是个很诡异的算法,感觉根本不是人想的,看了10多分钟才明白代码的意思,
先将任务按利润即权值降序排序,然后从前到后一次将其加入到答案中,添加时构造个辅助数组f,存的是天数,当任务i被选择,
则让f[i]指向i-1。
AC代码 利用了辅助排序函数 时间上超越了孔牛 跑了0.33S
#include
#include
using namespace std ;
const int maxn=100005;
int p[maxn],d[maxn];
int rank[maxn],f[maxn];
bool cmp (int a,int b)
{
return p[a]>p[b];
}
int find (int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int main ()
{
int n,i,j;
while (~scanf("%d",&n))
{
long long sum=0;
int maxd=n;//maxd初始化为n
for (i=0 ; i?=d[i];
}
sort(rank,rank+n,cmp);
for (i=0 ; i<=maxd ; i++)f[i]=i;
for (i=0 ; i