poj1018(1)

其实这道题我也没有完全的弄明白,糊里糊涂就ac了

 本文问题部分参考http://blog.csdn.net/lyy289065406/article/details/6676781

大致题意:

某公司要建立一套通信系统,该通信系统需要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的更不用枚举了,直接剪掉。 


package com.njupt.acm;
import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;


 /**
  * 关于题目中的sample input
  * 1 3 
  * 3 100 25 150 35 80 25 
  * 2 120 80 155 40 
  * 2 100 100 120 110
  * 
  * 其实应该有点问题,测试应该按一下输入:
  * 1  (测试用例数)
  * 3  (供应商个数)
  * 3 100 25 150 35 80 25   (第一个供应商提供的设备的情况)
  * 2 120 80 155 40   (第二个供应商提供的设备的情况)
  * 2 100 100 120 110 (第三个供应商提供的设备的情况)
  
  * @author Administrator
  *
  */
 public class POJ1018 {


     double bp = 0;


     public POJ1018() throws NumberFormatException, IOException {
         BufferedReader read = new BufferedReader(new InputStreamReader(
                 System.in));
         
         //记录测试用例的个数
         int t = Integer.parseInt(read.readLine());
         int num;
         int[][] b;
         int[][] p;
         int[] n;
         int bmin;
         int[] bmaxs;//保存最大带宽
         int bmax;
         String[] s;
         int sum;
         int temp;
         for (int i = 0; i < t; i++) {
        //num. 供应商的个数
             num = Integer.parseInt(read.readLine());
             
             //保存设备的带宽
             b = new int[num][];
             
             //保存设备的价格
             p = new int[num][];
             
             n = new int[num];
             
             bmin = Integer.MAX_VALUE;
             bmaxs = new int[num];//默认值全为0
             bmax = Integer.MAX_VALUE;
             for (int j = 0; j < num; j++) {
             
            //将每个供应商提供的设备的情况都保存到s数组里面
                 s = read.readLine().split(" ");
                 
                 //用n数组来保存某个供应商提供的设备的种类数
                 n[j] = Integer.parseInt(s[0]);
                 
                 
                 //用b[]来保存某个供应商提供的各种设备的带宽
                 b[j] = new int[n[j]];
                 
                 //用来保存某个供应商提供的设备的价格
                 p[j] = new int[n[j]];
                 
                 for (int k = 0; k < n[j]; k++) {
                     
                //k * 2 + 1 , 获得某个供应商提供的某种设备的带宽
                b[j][k] = Integer.parseInt(s[k * 2 + 1]);
                     
                /**
                 * if···语句的主要逻辑:
                 * 获得某个供应商所能提供的最大带宽
                 */
                if (b[j][k] > bmaxs[j]) {
                         
                bmaxs[j] = b[j][k];
                     }
                 
                 
                 
                /**
                 * if···语句的主要逻辑;
                 * 获得所有供应商中提供的最小带宽
                 */
                     if (b[j][k] < bmin) {
                         bmin = b[j][k];
                     }
                     
                     //获得某个供应商的某种设备对应的价格
                     p[j][k] = Integer.parseInt(s[k * 2 + 2]);
                 }
                 
                 
             }
             
            
             
             
             /**
              * for循环的主要逻辑:
              * 获得所有供应商中最大带宽中的最小值,保存在bmax中
              */
             for (int j = 0; j < num; j++) {
                 if (bmaxs[j] < bmax) {
                     bmax = bmaxs[j];
                 }
             }
             
             
             
             System.out.println("bmin:" + bmin);
             System.out.println("bmax:" + bmax);
             bp = 0;
             for (int j = bmin; j <= bmax; j++) {//在最小带宽和最大带宽之间做循环
                 
            sum = 0;
                 for (int k = 0; k < num; k++) {//在供应商之间循环
                     temp = Integer.MAX_VALUE;
                     for (int h = 0; h < n[k]; h++) {
                         /**
                          * if···语句的逻辑其实就是求最大B时的最小p
                          */
                    if (b[k][h] >= j && p[k][h] < temp) {
                             
                        //每一个供应商的设备的最小价格
                        temp = p[k][h];
                         }
                     }
                     
                     //获得每个供应商中,当b最大时且p最小时的p的价格之和
                     System.out.println("temp:" +temp);
                     sum += temp;
                 }
                 
                 /**
                  * if···语句的主要逻辑:
                  * 获得最大bp
                  */
                 if ((double) j / sum > bp) {
                 
                System.out.println( "j:"+j);
                System.out.println( "sum:"+sum);
                     bp = (double) j / sum;
                     System.out.println("bp:" + bp);
                 }
             }
             System.out.printf("%.3f\n", bp);
         }
     }


     public static void main(String[] args) throws NumberFormatException,
             IOException {
         new POJ1018();
         
        
     } 
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的东哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值