主要思路,这位美女大神已经有详细分析并给出代码了。
我这里也提出一点自己的小想法哈(跟上面的前辈有所不同),有待验证。
提炼一下题意:
共有n个devices;
每个device有m个manufactures;
每个manufacture有2个属性:带宽bw和价格pr;
目标是给每个device取一个manufacture(一旦一个device确定了它的manufacture,则这个device的bandwidth和price就被确定为其manufacture的bw和pr),并使全局的B/P的值最大,其中B为n个device中最小的,而P为n个device的price之和。
思路是这样的:【下面提到的B都为全局解的B值】
最优全局解{ B/P }中的“B”无非是所有manufacture的带宽中的某一个值;
那么,我们对所有的manufacture按照bw进行排序得到一个序列tmp[],我们会发现:
假如B为该序列中的某个,即B = tmp[i],那么其余device的manufacture的bw必须都大于tmp[i],即其余device的manufacture都在i之后; ①
设总manufacture数为M=Σmi,i=1,2...n;
我们不需要枚举所有M个B可能的值:
我们会先得到1个比较弱的结论:B的值不可能取到tmp[M-(n-1)+1],也就是这个下标之后无法提供n个manufacture;②
再想一个更强的结论:B的值不能比某个device中最大带宽的manufacture的带宽还大。③
根据结论③,我们可以推出下面一张图,找出一个n个数的序列:max bw of each device;再从这个序列中找出最小的那个MinofMax;假设其在tmp中的位置如下图右所标注;现在证明B可以取到Min Of Max的位置,也就是满足条件③必定满足条件②;也就是MinOfMax后需要提供至少n-1个属于不同device的manufacture,这必定成立,因为如左侧所示,MinOfMax是从n个device中选出来的,至少有n-1个属于不同device的manufacture的bw大于它(也可以有更多的manufacture大于它);
B不能取到Min Of Max之后的位置,因为至少有一个device无法提供比B大的bw。
那能否再缩小枚举的范围呢?答案应该是不能的,因为全局最优解很可能出现在Min of Max的位置,这样下面右侧的两个红色线条应该就可以理解其意义了吧?
综上所述,我们要枚举的部分也就是下图灰色部分。
确定了枚举范围,剩下的事就很好办了,将上图左侧每一行按照price的值升序排列,对于每一个枚举的B,每个device选择manufacture的标准是:bw大于B且price尽可能小,也就是排序后第一个出现的bw大于B的manufacture。
选择好每个device的manufacture之后求一下全局的B/P。枚举完所有可能的B值后选取一个最小的B/P.
下面给出我的代码:
#include <stdio.h>
#include <limits.h>
#include <algorithm>
using namespace std;
#define N 100 //devices num
#define M 100 //each device's manufacture num
#define CMPTYPE_BW 1
#define CMPTYPE_PR 2
typedef struct _manu{
int bw;
int pr;
}Manu;
Manu m[N][M];
int d[N];//each device's manufacture number
int type;
bool cmp(Manu a, Manu b){
if(type == CMPTYPE_BW)
return a.bw > b.bw;//降序
else
return a.pr < b.pr;//升序
}
int main(){
int t;
int B,P;
scanf("%d",&t);
while(t>0){
int n,mi;
int i,j;
scanf("%d",&n);
for(i = 0; i < n; i++){
scanf("%d",&mi);
d[i] = mi;
for(j = 0; j < mi; j++){
scanf("%d%d",&m[i][j].bw, &m[i][j].pr);
}
}
for(i = 0; i < n; i++){//each devices' manufacture sort by bw DESC
type = CMPTYPE_BW;
sort(m[i],m[i]+d[i],cmp);
/* for(int j = 0; j < d[i]; j++)
{
printf("%d ",m[i][j].bw);
}
printf("\n");*/
}
//get each device's max bw pick the min of those
int minbwm = INT_MAX;
for(i = 0; i < n; i++)
if(m[i][0].bw < minbwm)
minbwm = m[i][0].bw;
//printf("%d\n",minbwm);
for(i = 0; i < n; i++){
type = CMPTYPE_PR;
sort(m[i], m[i]+d[i],cmp);
}
int tmp[N*M];
int tmpind = 0;
for(i = 0;i < n; i++)
for(j = 0; j < d[i]; j++)
tmp[tmpind++] = m[i][j].bw;
sort(tmp,tmp + tmpind);
/* for(i = 0; i < tmpind; i++)
printf("%d ",tmp[i]);
printf("\n");
for(i = 0; i < n; i++){
for(int j = 0; j < d[i]; j++)
{
printf("%d ",m[i][j].pr);
}
printf("\n");
}*/
int Blast = -1,P;
double ratio = -1;
int pr;
for(i = 0; tmp[i] <= minbwm; i++){
B = tmp[i];P = 0;
if(B == Blast)
continue;
for(int k = 0; k < n; k++)
for(j = 0; j < d[k]; j++)
if(m[k][j].bw >= B){
P+=m[k][j].pr;
break;
}
Blast = B;
if(((double)B/P) > ratio){
ratio = ((double)B/P);
}
}
printf("%.3f\n",ratio);
t--;
}
//system("pause");
return 0;
}