题意:
软件公司有两个项目,每个项目有m个子项目,有n个程序猿,每个程序猿完成项目A或者
项目B的某一个子项目时间为x, y
每个人同一时刻只能做一个项目
项目完成时间是最晚完成的A或者B的时间,也就是说提早完成米有用
求最快完成项目需要的时间
乍一看很想背包问题,不过一时间又不清楚如何切入,把时间作为体积,每个人完成项目可以出现的次数为
每个人的分组的上限个数(即m,这样不会冲突),每个人的价值为1即完成一个部分
对于每一个时间计算是否满足要求需要,二分查找是否满足
n的上限是100,组数最大为100,需要按照分组背包优化成0-1背包问题
总之挺麻烦的,没胆切下去
看了别的解题报告,发现DP这个状态选择是一个很难也很关键的问题,如果设置为
d[i][j]表示前i个人,做j个A项目,最多可以做到B项目的个数
转移方程
d[i][j] = max { d[i][j] , d[i][j - k] + (time - A[i] * k) / B[i] }
即第i个人是做A呢还是做B呢
采用背包里面滚动数组的方法优化存储空间,时间复杂度大约在O(n * m * m)加二分,应该比一开始的想法快的多
状态如何设置是一门艺术。。
#include <iostream> #include <vector> #include <map> #include <list> #include <set> #include <deque> #include <stack> #include <queue> #include <algorithm> #include <cmath> #include <cctype> #include <cstdio> #include <iomanip> #include <cmath> #include <cstdio> #include <iostream> #include <string> #include <sstream> #include <cstring> #include <queue> using namespace std; ///宏定义 const int INF = 990000000; const int maxn = 110 ; const int MAXN = maxn; ///全局变量 和 函数 int max(int a, int b) { return a > b ? a : b; } int T; int n, m; int A[maxn], B[maxn]; int restmax[maxn]; int maxlim; bool ok(int n, int m, int V) { int i, j, k; memset(restmax, -1, sizeof(restmax)); //初始化第一个人 for (i = 0; i <= m; i++) { if (V < i * A[i]) break; restmax[i] = max(restmax[i], (V - i * A[1]) / B[1]); } if (restmax[m] >= m) return true; //对于每一个人 for (i = 2; i <= n; i++) { //做k项A时的最大值,从大到小按照状态方程刷新状态 for (k = m; k >= 0; k--) { //遍历做0-j的所有子情况,即当前第i个人做了j个A项目 for (j = 0; j <= k; j++) { if (V < j * A[i]) break; if (restmax[k - j] != -1) { restmax[k] = max(restmax[k], restmax[k - j] + (V - j * A[i]) / B[i]); } } } if (restmax[m] >= m) return true; } return false; } int solve(int n, int m, int V) { int s, e, mid; s = 0, e = maxlim; while (s < e) { mid = (s + e) / 2; if (ok(n, m, mid)) e = mid; else s = mid + 1; } return s; } int main() { //input ///变量定义 int i, j; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &m); int mm = -1; for (i = 1; i <= n; i++) { scanf("%d %d", &A[i], &B[i]); mm = max(mm, max(A[i], B[i])); } maxlim = mm * m * 2; //二分查找的上限 int ans = solve(n, m, maxlim); printf("%d\n", ans); } ///结束 return 0; }