POJ1018 Communication System 解题报告

http://poj.grids.cn/practice/1018

描述

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.

输入

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.

输出

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.
样例输入

1 3

3 100 25 150 35 80 25

2 120 80 155 40

2 100 100 120 110

样例输出

0.649

解体思路:

题目大意是有一个通信系统,系统由n个部分组成,每个部分由可以从mi个设备中选取。对于每个设备,都有其相应的通信带宽(bandwidth)和价格(price)。怎样选取设备能够使整个系统的B/P值最小。其中系统的B = min{mi.bandth}, P = sum{mi.price}

这道题看着不好下手,主要是应以什么量来进行搜索。考虑到系统的总体带宽是每部份带宽的最小值,我们可以以系统带宽为变量来进行搜索。

首先确定系统带宽的范围,既是每个设备带宽的最小和最大值。然后当带宽分别取最大、最小值之间的值时,找出相应B/P的最大值。

Max {Bk/sum(P)} while min_B <= Bk <= max_B

AC代码

内存:516KB     时间:30ms

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct Manufacture
{
int bandwidth;
int price;
};

Manufacture manu[101][101];

int main()
{
int test_case;
int num_dev;
int num_manufact[101];
int i, j, k;
int flag = 0;
int min_P, max_P;
int min_B, max_B;
int times, sum_price;
double max;

scanf("%d", &test_case);
while (test_case--)
{
flag = 0;
max = 0.0;
scanf("%d", &num_dev);
for (i = 0; i < num_dev; i++)
{
scanf("%d", &num_manufact[i]);
for (j = 0; j < num_manufact[i]; j++) {
scanf("%d %d", &manu[i][j].bandwidth, &manu[i][j].price);
if (flag == 0) {
min_B = max_B = manu[i][j].bandwidth;
flag = 1;
}
else {
if (manu[i][j].bandwidth > max_B)
max_B = manu[i][j].bandwidth;
else if (manu[i][j].bandwidth < min_B)
min_B = manu[i][j].bandwidth;
}
}
}

//遍历所有可能的带宽
for (k = min_B; k <= max_B; k++)
{
times = 0; sum_price = 0;
for (i = 0; i < num_dev; i++)
{
flag = 0;
for (j = 0; j < num_manufact[i]; j++)
{
//如果某一设备的带宽小于K值,则肯定不可能取
if (manu[i][j].bandwidth >= k)
{
if (flag == 0) {
min_P = manu[i][j].price;
flag = 1;
}
else {
//某一部分能取设备中的价格最小值
if (manu[i][j].price < min_P) {
min_P = manu[i][j].price;
}
}
}
}
if (flag == 1)
{
sum_price += min_P;
times++;
}
}
if (times == num_dev && (double)k/sum_price > max)
max = (double)k/sum_price;
}
printf("%.3lf\n", max);
}

return 0;
}

这道题其实还有更好的方法。上面在遍历带宽的时候,我们是遍历的最大值和最小值之间的所有值。但是实际上,我们的带宽只能取设备存在的带宽值。比如有三个设备的带宽分别为1、50、1000.那么我们在遍历的时候则会遍历1 ~ 1000,其实我们只用在1、 50、 1000 这三个值中找。

可以先对设备进行按照带宽排序,不分设备是第几部分的,如果带宽相同,则按照价格排序。那么我们在遍历的时候就可以从小到大进行选取,由于后面的带宽肯定是大于前面的带宽的,那么我们还少了manu[i][j].bandwidth >= k 带宽大小判断。具体的代码,读者可以自己去实现。



原文地址:https://www.cnblogs.com/lovesaber/p/2371618.html