动态规划法-1.独立任务最优调度问题C++实现

问题描述:

用2台处理机A和B处理n个作业。设第i个作业交给机器A处理时需要时间,若由机器B来处理,则需要时间。由于各作业的特点和机器的性能关系,很可能对于某些i,有,而对于某些j,j≠i,有。既不能将一个作业分开由2台机器处理,也没有一台机器能同时处理2个作业。设计一个动态规划算法,使得这2台机器处理完这n个作业的时间最短(从任何一台机器开工到最后一台机器停工的总时间)。研究一个实例:(a1,a2,a3,a4,a5,a6)=(2,5,7,10,5,2);(b1,b2,b3,b4,b5,b6)=(3,8,4,11,3,4)。

算法设计:

对于给定的2台处理机A和B处理n个作业,找出一个最优调度方案,使2台机器处理完这n个作业的时间最短。

数据输入:

由文件input.txt提供输入数据。文件的第1行是1个正整数n, 表示要处理n个作业。接下来的2行中,每行有n个正整数,分别表示处理机A和B处理第i个作业需要的处理时间。

结果输出:

将计算出的最短处理时间输出到文件output.txt中。    

输入文件示例

输出文件示例

input.txt

output.txt

6

2 5 7 10 5 2

3 8 4 11 3 4

15

问题分析:

对于这个问题,我们可以考虑,当完成第k个任务时,有两种可能:

    一是A处理机完成了第k个任务,那么B处理机完成k个任务的最短时间就与B处理机完成k-1个任务所需的最短时间是相同的

    二是B处理机完成了第k个任务,那么B处理机完成k个任务的最短时间就等于B处理机完成k-1个任务的最短时间加上B处理机完成第k个任务所需要的时间

设F[k][x]表示完成第k个任务时A耗费的时间为x的情况下B所花费的最短时间,其中0<=k <= n, 0<=x<= Σai,那么,状态转移方程为F[k][x]=minF[k−1][x−ak],F[k−1][x]+bk

处理好特殊情况(如x小于0时)开始填表即可。

最终的结果即是完成n个任务时A和B所需时间的较大值,即max(F[n][x], x).

算法实现:

 1 #include<iostream>
 2 #include<fstream>
 3 #include<string.h>
 4 using namespace std;
 5 
 6 int get_result(int a[],int b[],int n)
 7 {
 8     if(n==1)
 9         return min(a[0], b[0]);
10     int sum = 0,result = 10000;
11     for(int i=0;i<n;i++)
12     {
13         sum+=a[i];
14     }
15     int f[n][sum+1];
16     //初始化f(B处理用的时间)的各个元素为0 
17     memset(f, 0, sizeof(f));
18     
19     //初始化完成第一个任务时的情况
20     for(int x=0;x<a[0];x++)
21     {
22         f[0][x]=b[0];
23     } 
24     f[0][a[0]]=0;
25     
26     //动态规划过程
27     sum=a[0];
28     for(int k=1;k<n;k++)
29     {
30         sum+=a[k];
31         for(int x=0;x<=sum;x++)
32         {
33             if(x<a[k])
34             {
35                 f[k][x]=f[k-1][x]+b[k];
36             }
37             else
38             {
39                 f[k][x]=min(f[k-1][x-a[k]],f[k-1][x]+b[k]);
40             }
41             if(k==n-1)
42             {
43                 int val = max(x,f[k][x]);
44                 if(val<result)
45                     result = val;
46             }
47         }
48     }
49     return result;
50 }
51 
52 int main()
53 {
54     int n;
55     ifstream ifs;//创建文件流
56     ofstream ofs;
57     ifs.open("input.txt");
58     ofs.open("output.txt");
59     if(!ifs.is_open()||!ofs.is_open())
60     {
61         cout<<"open failed!"<<endl;
62         return 0;
63     }
64     ifs>>n;
65     int a[n+1],b[n+1];
66     for(int i=0;i<n;i++)
67     {
68         ifs>>a[i];
69     }
70     for(int i=0;i<n;i++)
71     {
72         ifs>>b[i];
73     }
74     int result=get_result(a,b,n);
75     cout<<result<<endl;
76     ofs<<result;
77     ifs.close();
78     ofs.close();
79     return 0;
80     
81 }

运行结果:

算法分析:

在get_result函数中,有两个嵌套for循环,时间复杂度为O(n*sum),所以时间复杂度为O(n2)。

经验归纳:

动态规划解题的一般思路:

1. 将原问题分解为子问题

把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决。

子问题的解一旦求出就会被保存,所以每个子问题只需求解一次。

2.确定状态

在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。

所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个问题的状态空间里一共就有N×(N+1)/2个状态。

整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。

3.确定一些初始状态(边界状态)的值

4. 确定状态转移方程

定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。

猜你喜欢

转载自www.cnblogs.com/pujianjian/p/12821419.html
今日推荐