題意:
軟件公司有兩個項目,每個項目有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;
}