思路:使用动态规划寻找到考虑所有问题后,机器A运行\(i\)分钟后,机器B运行的时间的最小值。之后再在所有的这\(i\)种情况中找到机器A和机器B共同运行的最小值。
\(dp[i][j]\)表示在做前i个任务中,机器A运行\(j\)分钟的情况下B机器运行的最短时间
解释:
在考虑第\(i\)个任务时,机器B在机器A运行\(j\)分钟的情况下的最小值应该是
前\(i-1\)个任务机器B在A运行\(j\)分钟的情况下的最小值加上B机器运行第\(i\)个任务的时间
以及将这个任务交给A机器运行前\(i-1\)个任务中A机器运行\(j-a[i]\)分钟时,B机器运行时间的最小值。
当\(dp[i][j]\)取到最优时,如果前\(i-1\)个任务机器B在A运行\(j\)分钟的最短时间\(dp[i-1][j]\)还可以更短,或者如果前\(i-1\)个任务机器B在A运行\(j-a[i]\)分钟的最短时间还可以更短,那么\(dp[i][j]\)的值就可以更小,与假设矛盾。
反证法:\(dp[n][j]\)是问题的解,对应着机器B运行时间的最小值。假设此时机器B的运行时间可以恰当增大,以此来使得总时间最小。那么,有下列三种情况:
一共有\(n\)种物品,所有物品的和为\(s\),因此子问题的规模大概是\(n*s\)个,解决一个子问题需要的复杂度为\(O(1)\),因此算法复杂度为\(O(sn)\),由于\(s\)可以特别大,所以这个算法不适用于\(s\)特别大的情况。
代码如下:
#include <iostream> #include <algorithm> using namespace std; int dp[105][10024]; int a[105]; int b[105]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) cin >> b[i]; int sum = 0; for (int i = 1; i <= n; i++) { sum += a[i]; //只考虑前i个,因此花时间最多不会超过前i个之和 for (int j = 0; j <= sum; j++) { int cur_val = 0x3f3f3f3f; if (j - a[i] >= 0) cur_val = dp[i - 1][j - a[i]]; dp[i][j] = dp[i - 1][j] + b[i]; if (dp[i][j] > cur_val) dp[i][j] = cur_val; } } int ans = 0x3f3f3f3f; for (int i = 0; i <= sum; i++) if (ans > max(dp[n][i], i)) ans = max(dp[n][i], i); for (int i = 1; i <= n; i++) { for (int j = 0; j <= sum; j++) cout<<dp[i][j]<<" "; cout<<endl; } cout << ans << endl; return 0; }