poj1018
来源:互联网 发布:小米max网络参数 编辑:程序博客网 时间:2024/06/05 00:17
大致题意:
某公司要建立一套通信系统,该通信系统需要n种设备,而每种设备分别可以有m1、m2、m3、...、mn个厂家提供生产,而每个厂家生产的同种设备都会存在两个方面的差别:带宽bandwidths 和 价格prices。
现在每种设备都各需要1个,考虑到性价比问题,要求所挑选出来的n件设备,要使得B/P最大。
其中B为这n件设备的带宽的最小值,P为这n件设备的总价。
解题思路:
首先需要明确,要使得B/P最大,自然是要令B尽可能大,P尽可能小。
由于B和P是两个相互制约的变量,而他们又要同时取得尽可能地取极值,那么可以先令其中一个值“暂时固定”下来。
令输入的行数就是设备的种类数,即第i行描述的是第i种设备,及提供第i种设备的厂家的产品信息。
使用枚举+剪枝的做法:
首先B的值肯定是厂家生产的所有设备中的某个带宽值,所以可以枚举所有的带宽,每次枚举B值时,B值就被“暂时固定”了。
其次,记录所选取的B是属于第k种设备的,再从余下的设备中,选取其余n-1种设备各一个,要求所选取的设备的带宽>=B(这是由题意确定的),而价格是要满足带宽的要求下的最小值。
当n种设备都选取后,计算B/P,然后再枚举下一个B,重复上述操作。比较不同的B值所得到的B/P值,选取最大的一个就是答案。
剪枝法:
准备工作:
1、输入时先记录:对于每种设备,厂家所提供的最大带宽MaxB[]
2、对所有设备(无论是否同种类)进行升序快排,以带宽为第一关键字,价格为第二关键字,设备所属的种类编号(1~n)为第三关键字。排序后存放在一维数组dev[]
剪枝:
1、 从小到大枚举dev[]中各个设备的带宽作为B值,设总设备数位m,则从1枚举到m-(n-1)。这是因为至少需要选择从枚举位置开始后面的n种设备,m-(n-1)是上限值,即恰好最后n件设备分别为n种设备。
2、 枚举B值的过程中,若发现B值比某种设备的最大带宽更大,则无需继续枚举,输出前面得到的B/P值。这是因为B是所有设备的最小带宽,若出现某个设备的最大带宽比B小,则说明B的选择是不合法的,又dev[]已按B升序排序,后面的B值更大,也不可能成立,因此无需继续枚举。
3、 枚举B值过程中,对于每个B值,在选择其他设备时要记录选取不同种类的设备个数count。最后当count<n时,说明B值位置往后剩余的设备中已无法提供n-1种不同设备,可直接跳出枚举。
剪枝2比较难懂,再稍微解释一下,以给的数据为例:
1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110
把该组数据升序排序,得到:
B: 80 100 100 120 120 150 155
P: 25 25 100 80 110 35 40
Id: 1 1 3 2 3 1 2
这样当B枚举到150的时候,即B=150,第三个供应商的所有设备都小于150,取任何一个设备都会导致B<150,矛盾。当然大于150的更不用枚举了,直接剪掉。
#include<iostream> #include<algorithm> #include<iomanip> using namespace std; class info { public: int B; //带宽 double P; //价格 int id; //设备号码 }; int cmp(const void* a,const void* b) { info* x=(info*)a; info* y=(info*)b; if((x->B)==(y->B)) //当带宽相等时 { if((x->P)==(y->P)) //当价格也相等时 return (x->id)-(y->id); //以编号为第三优先升序排序 return (x->P)-(y->P); //以价格为第二优先升序排序 } return (x->B)-(y->B); //以带宽为第一优先升序排序 } double max(double a,double b) { return a>b?a:b; } int main(int i,int j) { int test; cin>>test; for(int t=1;t<=test;t++) { int n; //设备数 int m=0; //生产商总数 cin>>n; int* MaxB=new int[n+1]; //各种设备对应的带宽最大值 info* dev=new info[100*100+1]; //记录所有厂家生产的产品信息 int pd=0; //dev[]指针 /*Input*/ for(i=1;i<=n;i++) { int mi; cin>>mi; m+=mi; MaxB[i]=-1; for(j=1;j<=mi;j++) { pd++; cin>>dev[pd].B>>dev[pd].P; dev[pd].id=i; MaxB[i]=max(MaxB[i],dev[pd].B); } } /*Qsort*/ qsort(dev,m+1,sizeof(info),cmp); /*Enum*/ bool flag=false; double ans=0; // B/P的最大值 for(i=1;i<=m-(n-1);i++) //枚举所有设备带宽的最小带宽B { //m-(n-1)是剪枝,因为当设备数>生产商数时就不必枚举了 bool* vist=new bool[n+1]; memset(vist,false,sizeof(bool)*(n+1)); vist[ dev[i].id ]=true; double price=dev[i].P; //设备总价 int count=1; //计数器,记录已经选取的设备个数 for(j=i+1;j<=m;j++) { if(vist[ dev[j].id ]) continue; if(dev[i].B > MaxB[ dev[j].id ]) //剪枝 { flag=true; //当前枚举的 "所有设备带宽的最小带宽Bi" 比 "设备j的最大带宽MaxBj" 要大 break; //说明当前Bi已经越界,无需继续往后枚举 } vist[ dev[j].id ]=true; price+=dev[j].P; count++; } if(flag || count<n) break; ans=max(ans,(dev[i].B/price)); } cout<<fixed<<setprecision(3)<<ans<<endl; delete MaxB; delete dev; } return 0; }
- POJ1018
- poj1018
- poj1018
- poj1018
- poj1018
- poj1018
- poj1018
- poj1018
- poj1018
- poj1018
- POJ1018
- poj1018
- poj1018
- poj1018
- poj1018
- POJ1018
- POJ1018
- poj1018
- ubuntu中安装中文输入法、输入法切换
- perl 正则匹配的次数
- 深入浅出解析OpenFlow
- 破解Revealapp的试用时间限制
- JAVA(五) ——类,对象,变量,方法,构造方法 【简解】
- poj1018
- JPA注解
- 指针参数传递时const指针使用
- bash shell 命令替换及引用
- byte[] to String (Java)
- Oracle 扩大表分区
- Linux物理内存概述
- 最优间隔分类器问题
- MFC下CSocket编程详解(CSocket 多线程)