poj 1018 選擇設備

從同的分組,每組“必須”選擇一個,使得總的最小帶寬 與 總費用的比值最大

一開始也沒想到怎麼DP法,但跟分組揹包問題很類似

分組揹包問題:

問題

有N件物品和一個容量爲V的揹包。第i件物品的費用是c[i],價值是w[i]。這些物品被劃分爲若干組,每組中的物品互相沖突,最多選一件。

求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

f[k][v]  = max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i屬於第k組}  第k組一件都不選或者選擇一件


最多選一件和必須選一件是不一樣的

類似的,對於這道題目建立狀態,一開始想到的是 d[i][j]   0 -- i - 1組花費爲j的時候所能獲得的最大帶寬

結論是d[n-1][p] / p 的最大值

轉移方程 d[i][j] =  max  {  d[i][s] (s <= j),    min{ d[i - 1][j - c[k] ] , b[k] }  即選擇第i組中第k個設備,帶寬爲b[k],花費爲c[k],從d[i-1][j - c[k]]轉移

那麼對於所有的費用需要進行累加,數值會非常大,而且對於組內的狀態d[i][j]更新計算比較複雜


換一種方式  d[i[j]表示第0-i-1組最大帶寬爲j的最小花費

結論是  j / d[i][j]的 最大值

轉移方程爲  d[i][j] =  min  { d[i][j] ,min {  d[i - 1][s] + c[k] } }    s  >= j 且 k爲第i組第c[k]個物品的花費

維護一個最大的帶寬maxb即可,不需要累加總的費用


poj 1018

#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 =500000000;
const int maxn = 1111;
///全局變量 和 函數
//
int T;
int d[maxn][maxn]; //第0-i組,帶寬爲j的最小花費d[i][j]
int b[maxn], p[maxn];
int main()
{
	int i, j;
	scanf("%d", &T);
	while(T--)
	{
		int n;
		scanf("%d", &n);
		int m;
		int maxb = -1;
		for(i = 0; i < n; i++)
		{
			for(j = 0; j < maxn; j++)
				d[i][j] = INF;
			scanf("%d", &m);
			//           maxb = -1;
			for(j = 0; j < m; j++)
			{
				scanf("%d %d", &b[j], &p[j]);
				maxb = max(maxb, b[j]);
			}

			//初始化第一組的數據
			if(i == 0)
			{
				for(j = 0; j < m; j++)
				{
					d[i][b[j]] = min(d[i][b[j]], p[j]);
				}
				continue;
			}

			for(j = 0; j <= maxb; j++)
			{
				//                d[i][j] = INF;
				if (d[i - 1][j] == INF)
					continue;
				for(int k = 0; k < m; k++)
				{
					int minb = min(j, b[k]);
					d[i][minb] = min(d[i][minb], d[i - 1][j] + p[k]);
				}
			}
		}
		double ans = -1;
		for(i = 0; i <= maxb; i++)
		{
			if (d[n - 1][i] != INF)
				ans = max(ans, double(i) /d[n - 1][i]);
		}
		printf("%.3f\n", ans);
	}
	return 0;
}


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