主要思路,这位美女大神已经有详细分析并给出代码了。
我这里也提出一点自己的小想法哈(跟上面的前辈有所不同),有待验证。
提炼一下题意:
共有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; }