参考:https://blog.csdn.net/LDUtyk/article/details/53995281
独立任务最优调度问题:
使用dp[i][j]数组表示的是第i个作业时,机器a花费不小于j时间的前提下,机器b完成作业i所需的最少时间。
当机器a在时间j的时候小于a[i]时,当然只能由b机器完成,
如果时间j大于a[i],那么考虑是由a还是b机器完成才好,
给a处理的话,b花费时间是dp[i-1][j-a[i]],
给b处理的话,b花费时间是dp[i-1][j]+b[i-1];
从中取小值作为dp[i][j]的值。
当所有工作分配完成之后,找出所有工作用时最少的时间。
所有工作完成的时间就是a机器与b机器耗费时间取大值。再从中选择小值作为结果。
分析:
当完成k个作业,设机器A花费了x时间,机器B所花费时间的最小值肯定是x的一个函数,设F[k][x]表示机器B所花费时间的最小值(注意,这是B机器所花费的时间,即当B机器停机时的时间点)。则有
F[k][x]=Min{ F[k-1][x]+b[k], F[k-1][x-a[k]] };
其中,F[k-1][x]+b[k]表示第k个作业由机器B来处理(完成k-1个作业时机器A花费的时间仍是x,前提就是A机器停机的时间是x),F[k-1][x-a[k]]表示第k个作业由机器A处理(完成k-1个作业时机器A花费的时间是x-a[k])。
那么x(表示A机器的停机时间)、F[k][x](表示B机器的停机时间)两者取最晚停机的时间,也就是两者中最大的时间,是在AB在此时间中完成k任务最终的时间:Max(x, F[k][x])。而机器A花费的时间x在此期间是一个变量,其取值可以是即x=0,1,2……x(max),(理论上x的取值是离散的,但为编程方便,设为整数连续的)由此构成了点对较大值序列。要求整体时间最短,取这些点对较大值序列中最小的即是。
理解难点在于B是A的函数表达式,也即动态规划所在。花点时间,看懂表达式,加上思考,理解了这点一切OK,后面的编程实现完全依据这个思想。先用前两个任务的枚举示例来帮助理解。
数据输入:
6
2 5 7 10 5 2
3 8 4 11 3 4
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
int minn = 0x3f3f3f3f;
int a[maxn]; //机器A处理每个作业的时间
int b[maxn]; //机器B处理每个作业的时间
int dp[maxn][maxn]; //表示完成i个作业且机器A花费j时间的条件下机器B所花费时间的最小值
int main()
{
int n, suma = 0;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a[i];
suma += a[i];
}
for(int i = 0; i < n; i++)
{
cin >> b[i];
}
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= suma; j++)
{
if(j < a[i - 1])//机器a在时间j的时候小于a[i]时,作业i只能由机器b完成
dp[i][j] = dp[i - 1][j] + b[i - 1];
else if(dp[i - 1][j - a[i - 1]] > dp[i - 1][j] + b[i - 1]) //选择较小时间
dp[i][j] = dp[i - 1][j] + b[i - 1]; //作业i由机器b处理
else
dp[i][j] = dp[i - 1][j - a[i - 1]]; //作业i由机器a处理
}
}
int temp;
for(int i = 0; i <= suma; i++)
{
temp = dp[n][i] > i? dp[n][i] : i;
if(temp < minn) //机器a与b所花时间取个大值
minn = temp; //求出最小
}
cout << "最短时间为: " << minn << endl;
return 0;
}