题意:有b块钱,要装一台电脑,给出n个配件各自的种类、品质因子和贾哥,要求每种类型的配件各买一个,总价不超过b,且“品质最差配件”的品质因子应尽量大,输出最小品质因子的最大值。
思路:解决“最小值最大”的常用方法就是二分答案。假设答案为x,那么删除品质小于x的所有配件,如果能组装出一台电脑,那么正确答案ans>=x,否则ans<x。
如何判定能组装出一台电脑呢?只要在删除品质小于x的所有配件后,取每种配件最便宜的一件,把价格加起来不超过b就可以了。
#include<cstdio>
#include<string>
#include<map>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 1005
#define INF 0x3f3f3f3f
using namespace std;
map< string,int > id;
int T,n,b,cnt;
char tmp[30];
struct Obj {int price,quality,type;}obj[MAXN];
bool cmp(Obj a,Obj b) {return a.quality<b.quality;}
int insert(string s)
{
if(!id[s]) id[s]=cnt++;
return id[s];
}
bool check(int x)
{
int sum=0,kind=0,cheapest[MAXN];
memset(cheapest,INF,sizeof(cheapest));//记录每件配件的最小价值,初始化都是INF
for(int i=1;i<=n;++i)
{
if(obj[i].quality<x) continue;//不考虑品质因子小于x的物品
if(cheapest[obj[i].type]==INF) ++kind,sum+=obj[i].price,cheapest[obj[i].type]=obj[i].price;
else if(obj[i].price<cheapest[obj[i].type]) sum=sum-cheapest[obj[i].type]+obj[i].price,cheapest[obj[i].type]=obj[i].price;
}
return sum<=b && kind==cnt-1;//如果总价不超过b,而且所选种数等于总种类数(也就是所有种类都选了一件),那么返回true,否则返回false
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&b);
cnt=1; id.clear();
int maxquality=0;
for(int i=1;i<=n;++i)
{
scanf("%s",tmp);
obj[i].type=insert(tmp);
scanf("%s",tmp);
scanf("%d %d",&obj[i].price,&obj[i].quality);
maxquality=max(maxquality,obj[i].quality);
}
int low=0,high=maxquality;
while(low<high)
{
int mid=low+(high-low+1)/2;
if(check(mid)) low=mid;
else high=mid-1;
}
printf("%d\n",low);
}
return 0;
}