问题描述
假设房前有两个处理机A、B,以及n个待处理的任务。第i个任务在处理处理机A上处理需要的时间为ai,在处理机B上处理的时间为bi,两个处理机可以并行处理任务,但单个处理机不能同时执行任务。要求给定n个任务及各个任务对应的ai 、bi,求得顺序完成这些任务所需要的最短时间。
思路分析
一个问题能否使用动态规划算法最主要的是确定它是否具有最优子结构性质,在证明最优子结构性质之后,再去找到状态转移方程,之后问题就简单多了。
对于这个问题,我们可以考虑,当完成第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] = min{F[k-1][x-a_k], F[k-1][x] + b_k} \]
处理好特殊情况(如x小于0时)开始填表即可。
最终的结果即是完成n个任务时A和B所需时间的较大值,即max(F[n][x], x).
最重要的就是想明白状态转移方程代表的是什么,F代表的是B的最短时间,一定要牢记这一点,我在模拟的过程中很容易搞晕这一点
例子
可以用于模拟
- n=6
- a:2, 5, 7, 10, 5, 2
- b:3, 8, 4, 11, 3, 4
最终结果为15。
代码
#include<iostream> #include<string.h> using namespace std; int get_result(int a[],int b[], int n){ if(n==1)return min(a[0], b[0]); int sum=0, result = 10000; for(int i = 0;i < n;i++)sum += a[i]; int f[n][sum+1]; //初始化f的各个元素为0 memset(f, 0, sizeof(f)); //初始化完成第一个任务时的情况 for(int x = 0;x < a[0];x++)f[0][x] = b[0]; f[0][a[0]] = 0; //这里开始动规的过程 sum = a[0]; for(int k = 1;k < n;k++){ sum += a[k]; for(int x = 0;x <= sum;x++){ //处理x<0时设为无穷大的情况 if(x-a[k] < 0){ f[k][x] = f[k-1][x]+b[k]; } else f[k][x] = min(f[k-1][x-a[k]], f[k-1][x]+b[k]); if(k == n-1){ int val = max(x, f[k][x]); if(val < result)result = val; } } } return result; } int main() { int n; cin >> n; int a[n], b[n]; for(int i = 0;i < n;i++)cin >> a[i]; for(int i = 0;i < n;i++)cin >> b[i]; int result = get_result(a, b, n); cout << "花费的最短时间为: " << result << endl; }