POJ 1018:Communication System - DP

本文解析了POJ1018题目中的通信系统问题,通过动态规划算法解决如何从多个厂家中选择网线以获得最大的性价比。介绍了状态转移方程和实现代码。
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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值