POJ 1018
题意:
某公司要建立一套通信系统,有n个厂家提供生产所需要的网线。而每个厂家生产的同种网线都会存在两个方面的差别:带宽bandwidths
和 价格prices。
现在需要在每个厂家选择一件网线,考虑到性价比问题,要求所挑选出来的n件设备,要使得B/P最大。输出这个比值保留3位小数。(其中B为这n件设备的带宽的最小值,P为这n件设备的总价。)
思路:
dp[i][j]:取到第 i 个厂家的网线,其中最小带宽为 j 的最小费用。i代表的是选取前i个物品,j为当前最小的带宽。
选择第i个厂家时,需要枚举该厂家的所有网线,选择该k网线时,和不选择该k网线。则
dp[i][final] = min(dp[i - 1][j] + p[k], dp[i][final])。
此处final = min(j,b[k])。计算结果时所用的带宽是最小值,故枚举时需要考虑的是最小带宽。
状态转移方程:dp[i][j] = min(dp[i - 1][k] + p, dp[i][j]);
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[110][1200];//dp[i][j]:取到第 i 个厂家的网线,其中最小带宽为 j 的最小费用
int b[110], p[110];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m, maxb = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++)
for(int j = 0; j < 1200; j++)
dp[i][j] = inf;
memset(b, 0, sizeof(b));
memset(p, 0, sizeof(p));
for(int i = 0; i < n; i++){
scanf("%d", &m);
for(int j = 0; j < m; j++){
scanf("%d%d", &b[j], &p[j]);
maxb = max(maxb, b[j]);
}
if(i == 0){
for(int j = 0; j < m; j++)
dp[0][b[j]] = p[j];//保证不会出现 b相同但是p不同
continue;
}
int tmp;
for(int k = 0; k <= maxb; k++){
for(int j = 0; j < m; j++){
tmp = min(k, b[j]);
dp[i][tmp] = min(dp[i][tmp], dp[i - 1][k] + p[j]);
}
}
}
double ans = 0.0;
for(int i = 0; i <= maxb; i++){
if(dp[n - 1][i] != inf)// (n - 1)p写成n了 弄得答案一直不对 ********** 1
ans = max(ans, 1.0 * i / dp[n - 1][i]);
}
printf("%.3lf\n", ans);// 这里居然一直没把ans写进去搞得一直0.000O…晕… ************ 2
}
return 0;
}