CCh99

贪心算法实验题

东 华 大 学

《算法分析设计与综合实践》实验报告

 

学生姓名:曹晨学号:171310402 指导教师:章昭辉

实验时间:2019-4-9 实验地点:图文信息大楼三号机房

 

  1. 实验名称

    贪心算法

  2. 实验目的
    1. 理解贪心算法的概念。
    2. 掌握贪心算法的基本要素。
    3. 了解适用贪心算法的问题类型,并能设计相应的算法。
  3. 实验内容
    1. 最优服务次序问题

      问题描述设有n个顾客同时等待一项服务,顾客i需要的服务时间为ti(1<=i<=n)。应如何安排n个顾客的服务次序才能使平均等待时间最小?平均等待时间是n个顾客等待服务时间的总和除以n。

      算法设计:对于给定的n个顾客需要的服务时间,计算最优服务次序。

      数据输入:由文件input.txt提供输入数据。第1行是正整数n,表示有n个顾客。接下来的1行中,有n个正整数,表示n个顾客需要服务的时间。

      结果输出:将计算的最小平均等待时间输出到文件output.txt。

    2. 非单位时间任务安排问题

      问题描述:具有截止时间和误时惩罚的任务安排问题可描述如下

      1. 给定n个任务的集合S={1,2,….,n};
      2. 完成任务i需要ti时间,1<=i<=n;
      3. 任务i的截止时间di(1<=i<=n),即要求任务i在时间di之前结束
      4. 任务i的误时时间wi(1<=i<=n),即任务i未在时间di之前结束,将招致wi的惩罚,若按时完成,则无惩罚。

        任务安排要求确定一个S的时间表(最优时间表)使得总误时惩罚达到最小

      算法设计:对于给定的n个任务,计算总误时惩罚最小的最优时间表

      数据输入:由文件input.txt给出输入数据。第1行是一个正整数n,表示任务数。接下来的n行中,每行有3个正整数a、b、c,表示完成相应任务需要时间a,截止时间为b,误时惩罚值为c。

      结果输出:将计算的总误时时间输出到文件output.txt。·

  4. 实验过程
    1. 研究一个实例:有10个顾客,所需服务时间分别为56 12 1 99 1000 234 33 55 99 812

      用t[i]来表示每个顾客所需的服务时间,T[i]表示等待的时间。假设已知一个最优服务次序A={t(1),t(2),…t(n)};按照此顺序每个顾客的等待时间为:T(1)=t(1),T(2)=t(1)+t(2),…….,T(n)=t(1)+t(2)+….+t(n);总的等待时间为sum=T(1)+T(2)+….+T(n);可以看出t(1)被加了n次, t(2)被加了n-1次,依此类推,直到t(n)被加一次后结束,除以n就等于平均等待服务时间。运用贪心策略,即最短服务时间优先。将t[i]按照递增的顺序排序,所得的序列就是最优服务序列。

顾客编号

1

2

3

4

5

6

7

8

9

10

服务时间

1

12

33

55

56

99

99

234

812

1000

等待时间

1

13

46

101

157

256

355

589

1401

2401

算法描述:

 

1 //求最短平均等待时间的函数

2 int Findbest(int *t,int n)//n是顾客的个数,t[n]用来存放每个顾客所需的服务时间

3 {

4 sort(t,t+n);//从小到大递增排列数组t

5 int sum=0;//总的等待时间初始化0

6 for(int i to n)

7 sum+=t[i]*(n-i);//从1到n遍历最优服务次序,并加上各个等待服务时间

8 sum=sum/n;//求平均等待服务时间

9 return sum;

10 }

 

  1. 定义一个结构体Task包含三项数据。

    struct Task

    {

    int a;//所需时间

    int b;//截止时间

    int c;//惩罚值

    };

    首先将任务按其截止时间递增排序。假设对于任务1,2,…..,n,如果截至时间为d,则最小的误时惩罚为p(i,d);

    其中p(i,d)={p(i-1,d)+t[i].c,p(i-1,min(d,t[i].a))}

    p(i-1,d)+t[i].c表示不做第i个任务时的误时惩罚值,p(i-1,min(d,t[i].a))表示要做第i个任务时的误时惩罚值,条件是必须在截止时间之前做完它。

    对于第一个任务,如果时间小于它完成时间,那么遭受惩罚,否则的话做第一个任务

    对于第i个任务,如果时间小于它的完成时间,不能执行,惩罚值等于上一个任务当前时间加上第i个任务的惩罚值,如果大于则比较不能完成时的惩罚值和完成这个任务所得的惩罚值,取二者最小的那个。下图是一个实例的表。该例子为n=7;(1,4,70)(2,2,60)(1,4,50)(1,3,40)(1,1,30)(1,4,20)(3,6,80);

任务编号

截至时间0

1

2

3

4

5

6

0

30

0

0

0

0

0

0

1

90

60

30

30

30

30

30

2

130

90

60

30

30

30

30

3

200

130

90

60

30

30

30

4

250

180

130

90

60

60

60

5

270

200

150

110

80

80

80

6

350

280

230

190

160

150

110

 

算法描述:

1 //sort的自定义排序函数

2 bool comp(Task x,Task y)

3 {

4 if(x.b<y.b)//根据截至时间的大小进行非减排序

5 return true;

6 else return false;

7 }

8 //求最小惩罚值的函数

9 int Leastime(Task *t,int n)//t数组代表任务的三个参数,n代表任务的个数

10 {

11 sort(t,t+n,comp);//根据缩写的comp函数排列数组(非减)

12 int d=t[n-1].b;//最大的截止时间d

13 int p[n][d+1];//二维数组p来代表p(i,d)时的最小惩罚数

14 memset(p,999,sizeof(p));//初始化数组

15 for(int i=0 to d)//遍历二维数组的第一行,有时间做该任务,惩罚值为0,否则惩罚值为t[0].c

16 p[0][i]=(i>=t[0].a)?0:t[0].c;

17 for(int i=1 to n)//遍历剩下的二维数组,

18 for(int j=0 to d)

19 p[i][j]=p[i-1][j]+t[i].c;//首先考虑不做当前任务的惩罚值

20 int h=t[i].b<j?t[0].b:j;//如果有时间做的话

21 if(h>=t[i].a&&p[i][j]>p[i-1][[h-t[i].a])//跟不做任务相比较

22 p[i][j]=p[i-1][h-t[i].a]//如果不做任务大于做任务的惩罚值,则做任务,改变p[i]j]的值

23 return p[n-1][d];//返回最小惩罚值

24 }

 

  1. 结果分析
    1. 答案是532

       

      这道题非常的简单,用到了贪心算法的思路,通过短短几步就能求解出答案。

      时间复杂度:一个for循环用来求总的等待服务时间

      F(n)=n=O(n)

      空间复杂度:一个一维数组t[n]用来存放各个顾客所需的服务时间

      F(n)=n =O(n);

    2. 答案是110

      这个题目是我觉得用动态规划的方法做出来的,因为有比较,做该任务和不做该任务的比较,贪心算法应该把两种情况都写入表中,但是只选了最优的方法

      时间复杂度:

      F(n)=n*logn+n*d=O(n*logn+n*d)

      空间复杂度:用一维结构体数组分别来存放该任务的三个属性,一个二维数组用来存放在截止时间为d,i个任务的最小惩罚值

      F(n)=3*n+n*d=O(n+n*d);

  2. 实验总结

附录:(要求代码里各行要有注释

见打包文件

 

posted on 2019-04-09 21:43  CCh99  阅读(1419)  评论(0编辑  收藏  举报

导航