JOJ2645 Working in JLU (任务调度 贪心算法 并查集 )

 

实验题目:用贪心算法解决作业调度问题。

实验目的

1.      学习带时限的作业调度—最大时限选择方法。

2.      掌握贪心算法的应用。

问题描述:

给定任务序列J1J2 ...Jn,假定只有一台处理机为这批作业服务。每件任务Ji给定一个时限di和对应利润Pi。只有在规定时限之内完成作业,才会得到利润Pi。通过设计合适的算法选择和安排任务子集Ji,使得J中的每个作业都能在各自的时限内完工,且使获得的利润∑Pi总和最大。

d=max{di} 1inb=min{n,d}

任何最大利润的可完工子序列中的作业个数必不大于b。

解答方法:

1. 将任务按时限划分集合,时限按从大到小排列

d=max{di} 1in

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

预计输出:

作业执行序列为: J3J1J6J7

最大利润为:70

不过这个算法对于N为10^5是超时的,TLE代码:


#include <cstdio>
#include <algorithm>

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 ; i<n ; ++i)
        { 
            scanf("%d%d",p+i,d+i),rank[i]=i;
            if(d[i]>maxd)maxd=d[i];
        }
        sort(rank,rank+n,cmp);
        int m=n;
        for (i=maxd ; i>0 ; --i)
        {
            for (j=0 ; j<n ; ++j)
            {
                if(!vis[rank[j]] && d[rank[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 <cstdio>
#include <algorithm>

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<n ; ++i)
        { 
            scanf("%d%d",p+i,d+i);
            rank[i]=i;
            maxd>?=d[i];
        }
        sort(rank,rank+n,cmp);
        for (i=0 ; i<=maxd ; i++)f[i]=i;
        for (i=0 ; i<n ; i++)
        {
            int father=find(d[rank[i]]);
            if(father)
            f[father]=father-1,sum+=p[rank[i]];
            //printf("%d\t",father);
        }
        printf("%lld\n",sum);
    }
    return 0;
}


 

 

 

你可能感兴趣的:(JOJ2645 Working in JLU (任务调度 贪心算法 并查集 ))