Codejam之Ratatouille

来源:互联网 发布:amarra for mac 编辑:程序博客网 时间:2024/06/01 18:57

问题描述

每一个包裹含有一定量的原料,不同的包裹即使含有相同的原料,量可能不一样。对于每一种原料,你有相同数量的包裹。

用这些包裹组成尽可能多的套装(kit)提供给顾客。一个kit中对每一种原料都含有1个包裹,一个kit可以做成多份ratatouille(这个kit的label,必须是整数)。为了不浪费,每个包裹所包含的原料的量必须在做成label份ratatouille实际用量的90%到110%之间。

比如,做成一份ratatouille需要500g西红柿和300g洋葱,现有一个900g的西红柿包裹,和一个660g的洋葱包裹,这两个包裹可以组成一个kit,做成2份ratatouille(包裹的label是2)。做成两份ratatouille需要西红柿1000g,洋葱600g,900g在1000g的[90%, 110%]之间,660g在600g的[90%, 110%]之间,因此可以组成kit。

目的是组成尽可能多的kit,每个包裹至多只能用在一个kit中,注意目的不是做成尽可能多份ratatouille

输入:
第一行T,代表有T个测试用例
每个测试用例如下:
一行两个数字,N(需要多少种原料),P(每个原料的包裹的数量)
一行N个数字Ri,Ri代表做成一份ratatouille需要多少g第i种原料
N行,每行P个数字,第i行的第j个数值Qij代表包含第i种原料的第j个包裹包含多少g这种原料。

输出:
最多能够组成多少个kit

限制:
1<=T<=100
1<=Ri<=106
1<=Qij<=106

小数据集:
1<=N<=2
1<=P<=8

大数据集:
1<=N<=50
1<=P<=50
N×P<=1000
这里写图片描述

问题解决

Q=包裹中含有该原料的量
R=做成一份ratatouille需要该原料的量
m × R × 90% <= Q <=110% × m × R
所以Q / ( 1.1R ) <= m <= Q / ( 0.9R )
包裹装了多少g原料是不重要的,重要的是包裹能够用于哪些label的kit,通过上面的不等式可以得到一个range,注意range可以为空(如R=10,Q=15)

public static class range{    int s;    int e;    public range(int s,int e){        this.s=s;        this.e=e;    }}//ingre_no 需要多少种原料//pack_no 每种原料有多少个包裹//ingre_needs[1...ingre_no] 做一份ratatouille需要原料i多少gList[] packs = new LinkedList[ingre_no+1];for(int i=1;i<=ingre_no;i++){    aline=reader.readLine();    List<range> lis=new LinkedList<range>();    for(int j=1;j<=pack_no;j++){        int pack_gram=Integer.parseInt(aline.split(" ")[j-1]);        //计算这个包裹的range                      int s=(10*pack_gram)/(ingre_needs[i]*11)+(((10*pack_gram)%(ingre_needs[i]*11)==0)?0:1);        int e=(10*pack_gram)/(ingre_needs[i]*9);        if(s<=e){    //如果range为空,无需进入列表            lis.add(new range(s,e));        }    }    range[] packi =new range[lis.size()];    lis.toArray(packi);    sort(packi);   //对range进行排序,s小的在前面,如果s相等比较e,e小的在前面    lis.clear();    for(int j=0;j<packi.length;j++){        lis.add(packi[j]);    }    packs[i]=lis;}

针对每一种原料,读取这种原料的包裹的含量并计算range,加入列表。对列表进行排序,s小的在前面,如果s相等再比较e,e小的在前面。

如果只需要一种原料,结果就是该原料对应的列表的大小,即有多少个range不为空的包裹就能组成多少个kit。

如果有N种原料,遍历N种原料,如果有一个原料对应的列表为空,则不可能组成一个kit。

取出N种原料对应的N个列表的第一个range
1. 这N个range的交集不为空,则可以组成一个kit,去掉这N个range。
2. 这N个range的交集为空,去掉上界最小的哪个range
重复这一步骤直至有列表为空。

int res=0;if(ingre_no==1){    res=packs[1].size();}else{    boolean flag=true;    for(int i=1;i<=ingre_no;i++){        if(packs[i].size()==0){            flag=false;        }    }    while(flag){        boolean flag2=true;        int most_low_upper=1;        range r1=(range)packs[1].get(0);        for(int i=2;i<=ingre_no;i++){            range r2=(range)packs[i].get(0);            if(r2.e<r1.e) most_low_upper=i;            if(r2.s>r1.e || r2.e<r1.s){                flag2=false;            }        }        if(flag2){            res++;            for(int i=1;i<=ingre_no;i++){                packs[i].remove(0);            }        }else{            packs[most_low_upper].remove(0);        }        for(int i=1;i<=ingre_no;i++){            if(packs[i].size()==0){                flag=false;            }        }    }}writer.write("Case #"+k+": "+res+'\n');
原创粉丝点击