POJ 1018 dp问题的一般过程

做dp问题已经有一段时间了。虽然感觉dp算法的思路还不是那么清晰,但是思维和以前比已经有了巨大的进步。在这儿,我想借poj中的一道题,对dp问题进行一个小小的总结。成长的路还有很长很长。

Communication System

Description

We have received an order from Pizoor Communications Inc. for a special communication system. The system consists of several devices. For each device, we are free to choose from several manufacturers. Same devices from two manufacturers differ in their maximum bandwidths and prices. 
By overall bandwidth (B) we mean the minimum of the bandwidths of the chosen devices in the communication system and the total price (P) is the sum of the prices of all chosen devices. Our goal is to choose a manufacturer for each device to maximize B/P. 

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by the input data for each test case. Each test case starts with a line containing a single integer n (1 ≤ n ≤ 100), the number of devices in the communication system, followed by n lines in the following format: the i-th line (1 ≤ i ≤ n) starts with mi (1 ≤ mi ≤ 100), the number of manufacturers for the i-th device, followed by mi pairs of positive integers in the same line, each indicating the bandwidth and the price of the device respectively, corresponding to a manufacturer.

Output

Your program should produce a single line for each test case containing a single number which is the maximum possible B/P for the test case. Round the numbers in the output to 3 digits after decimal point. 

Sample Input

1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110

Sample Output

0.649
题目的原意如下:要组建一个电信系统,需要若干台设备,每一台设备都有若干个制造商提供。但是,每一个制造商提供的设备其带宽(B)(定义为这若干台设备中的最小带宽)和造价(P)(定义为若干台设备中的总造价)均不相同。所以我们要得到的是B/P的最小值。

首先我们刻画最优解的特征:最优解对应的一个最小的带宽所花费的总造价一定是最低的。而且必须n台设备都有挑选。所以,刻画一个数组dp[i][j],表示的是达到第i台选择完毕之后,带宽达到j时的最小代价。再起一个结构体数组data[i][j]表示每一台设备的带宽和造价。

输入之后,我们得到了转移方程:dp[i][k]=min(dp[i-1][k]+data[i][j].p,dp[i][k])(k<=data[i][j].b)如果先进行排序会更好,不过我直接将数据分为两个转移方程来处理,可能麻烦一些。再有就是注意初始化的问题,对于第一台设备,直接复制data的数据,即dp[1][data[1][j].b]=data[1][j].p最后可以得到结果。

下面贴代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define MAX 0x3f3f3f3f
using namespace std;
struct device
{
	int b, p;
};
device data[102][102];
int dp[102][1210], maxm, t, mi[102], num;
float maxi(float a, float b)
{
	if (a > b)return a;
	else return b;
}
void process()
{
	int i, j, k;
	float result = 0;
	memset(dp, MAX, sizeof(dp));
	for (i = 1; i <= num; i++)
		for (j = 1; j <= mi[i]; j++)
		{
			if (i == 1)
				dp[i][data[i][j].b] = data[i][j].p;
			else
			{
				for (k = 1; k <= maxm; k++)
				{
					if (k <= data[i][j].b)dp[i][k] = min(dp[i][k], dp[i - 1][k] + data[i][j].p);
					else dp[i][data[i][j].b] = min(dp[i][data[i][j].b], dp[i - 1][k] + data[i][j].p);
				}
			}
		}
	for (i = 1; i <= maxm; i++)
	{
		result = maxi(result, (float)i / dp[num][i]);
	}
	printf("%.3f\n", result);
}
int main()
{
	int i, j;
	cin >> t;
	while (t--)
	{
		maxm = 0;
		cin >> num;
		for (i = 1; i <= num; i++)
		{
			cin >> mi[i];
			for (j = 1; j <= mi[i]; j++)
			{
				cin >> data[i][j].b >> data[i][j].p;
				maxm = max(maxm, data[i][j].b);
			}
		}
		process();
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值