hoj 2608 Assemble

Assemble

Recently your team noticed that the computer you use to practice for programming contests is not good enough anymore. Therefore, you decide to buy a new computer.

To make the ideal computer for your needs, you decide to buy separate components and assemble the computer yourself. You need to buy exactly one of each type of component.

The problem is which components to buy. As you all know, the quality of a computer is equal to the quality of its weakest component. Therefore, you want to maximize the quality of the component with the lowest quality, while not exceeding your budget.

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:

  • One line with two integers: 1 ≤ n ≤ 1 000, the number of available components and 1 ≤ b ≤ 1,000,000,000, your budget.
  • n lines in the following format: "type name price quality", where type is a stringwith the type of the component, name is a string with the unique name of the component, price is an integer (0 ≤ price ≤ 1 000 000) which represents the price of the component and quality is an integer (0 ≤ quality ≤ 1,000,000,000) which represents the quality of the component (higher is better). The strings contain only letters, digits and underscores and have a maximal length of 20 characters.

It will always possible to construct a computer with your budget.

Output

Per testcase: One line with one integer: the maximal possible quality.

Sample Input

1
18 800
processor 3500_MHz 66 5
processor 4200_MHz 103 7
processor 5000_MHz 156 9
processor 6000_MHz 219 12
memory 1_GB 35 3
memory 2_GB 88 6
memory 4_GB 170 12
mainbord all_onboard 52 10
harddisk 250_GB 54 10
harddisk 500_FB 99 12
casing midi 36 10
monitor 17_inch 157 5
monitor 19_inch 175 7
monitor 20_inch 210 9
monitor 22_inch 293 12
mouse cordless_optical 18 12
mouse microsoft 30 9
keyboard office 4 10

Sample Output

9

  1. 这道题是个二分题目,先将各部件归类,然后二分枚举价值,找到在可消费范围内价值的最大值。有几个技巧或者优化:1.归类时可以用map(我没用,是看到别人的程序学习到的)2.当枚举价值v时,查询某一类中不小于此价值的最小值时,可以用lower_bound,免得再来一次二分3.由于价值的区间较大,可以离散化一下进行优化,因为结果一定是某个部件的价值。离散时用unique函数感觉此题又有点像背包,但背包似乎又求多了。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1010
using namespace std;
int t,n,m,left,right,nLeft,nRight,mid,ans,nMid,totpart,moneyLeft;
int f[N];

/**********************************************
*部件类                                       *
*存放每一个部件的名字(类型),价格,价值   *
**********************************************/
struct CPart
{
    char m_sName[21];
    int m_nPrice;
    int m_nValue;
    void Input()
    {
        scanf("%s %*s %d %d",m_sName,&m_nPrice,&m_nValue);
    }
    void Output()
    {
        printf("%s %d %d\n",m_sName,m_nPrice,m_nValue);
    }
    //按照名字,价格,价值的顺序排序
    bool operator<(const CPart &b)const
    {
        int k;
        if((k = strcmp(m_sName,b.m_sName))==0)
        {
            if( m_nPrice != b.m_nPrice )
                return m_nPrice < b.m_nPrice;
            return m_nValue > b.m_nValue;
        }
        return k<0;
    }
} p[N];

//只按照价值排序的比较函数
bool cmp(CPart *const &a,CPart *const &b)
{
    return a->m_nValue < b->m_nValue;
}

/*****************************************
*同一类部件构成的类                     *
*****************************************/
struct CWhole
{
    CPart *m_pPart[N];
    int m_nTotType;
    //向此类部件添加元素
    void Push(CPart *b)
    {
        if(m_nTotType)
        {
            //由于是按照价格从小到大添加的,所以价格大而价值小的直接剔除
            if(m_pPart[m_nTotType-1]->m_nValue>=b->m_nValue)return;
        }
        m_pPart[m_nTotType++]=b;
    }
    //返回这类部件最高的价值
    int GetRight()
    {
        return m_pPart[m_nTotType-1]->m_nValue;
    }
    //返回这类部件最低的价值
    int GetLeft()
    {
        return m_pPart[0]->m_nValue;
    }
    //重定义[],为了方便,你懂得。。。。
    CPart *operator[](const int i)
    {
        return m_pPart[i];
    }
    //返回价值不小于v的部件中价格最小的
    int Find(int v)
    {
        CPart *k;
        k = new CPart;
        k->m_nValue = v;
        return (*lower_bound( m_pPart, m_pPart + m_nTotType, k, cmp))->m_nPrice;
    }
} a[N];

void input()
{
    scanf("%d %d",&n,&m);
    for(int i = 0; i < n ; i++ )
    {
        p[i].Input();
    }
}

//求出待查找的价值区间上界,上界只可能是各类部件上界的最小值
void GetRight()
{
    right = a[ 0 ].GetRight();
    for( int i = 1 ; i < totpart ; i++ )
    {
        right = min( right, a[ i ].GetRight());
    }
    right = lower_bound(f,f+n,right) - f;
}

//求出带查找的价值区间下界,下界是各类部件下界的最小值
void GetLeft()
{
    left = a[ 0 ].GetLeft();
    for( int  i = 1 ; i < totpart ; i++ )
    {
        left = min(left, a[i].GetLeft());
    }
    left = lower_bound(f, f+n, left) - f;
}

//将各部件分类,放入a中
void makeA()
{
    a[0].Push( &p[ 0 ] );
    for( int i = 1; i < n; i++ )
    {
        if( strcmp(p[ i ].m_sName, p[i-1].m_sName) )
        {
            totpart++;
        }
        a[ totpart - 1 ].Push( &p[ i ] );
    }
}

//将价值离散化,放入f中
void makeF()
{
    for(int i = 0 ; i < n ; i++ )
    {
        f[ i ] = p[ i ].m_nValue;
    }
    sort(f,f+n);
    n = unique(f,f+n) - f;
}


void init()
{
    totpart = 1;
    memset(a,0,sizeof(a));
    sort( p, p+n );
    makeA();
    makeF();
    GetRight();
    GetLeft();
}

//二分查找
void solve()
{
    while(left<=right)
    {
        mid = ( left + right ) / 2;
        moneyLeft = m;
        for( int i = 0 ; i < totpart && moneyLeft >= 0; i++ )
        {
            moneyLeft -= a[i].Find(f[ mid ]);
        }
        if(moneyLeft<0)right = mid - 1;
        else
        {
            ans = mid;
            left = mid + 1;
        }
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        input();
        init();
        solve();
        printf("%d\n",f[ans]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值