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.归类时可以用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;
}