問題描述
假設房前有兩個處理機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;
}