poj 1973 分配任務 進階動態規劃

題意:

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章