本题二分
最大值最小,或者最小值最大类似的问题,多用二分解。
基本思想,如果依次查找quality最小的值,如果能成功拼出电脑则肯定>= 当前的quality的值,不能则肯定< 当前quality。二分查找,确保每次中间值比最小值大,则可确保Right-left == 1 时,中间值为right。为什么要确保mid=right,因为当mid值满足装机要求的时候,答案>= mid,所以left 只能赋值为mid(这里的left 和到right是闭区间),mid==left则最终left值不变,会无限循环下去。 mid=right 的话,之后要么是装机失败当前mid值太大right = mid -1,要么是装机成功答案>= mid,left =mid == right,所以最终状态肯定是left == right,则left的值就是答案。
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const int MAX = 1000+5,INF = 1000000000+100,MIN = -1;
int n;
int b,max_q,min_q;
struct component
{
int price;
int quality;
}c[MAX][MAX];//c[i][0]price用来记录 该种类配件数量
vector<string>type;
int Id(const char* s)
{
string str(s);
int size = type.size();
for(int i = 0; i < size; i++)
if(type[i] == str)return i;
type.push_back(str);
return size;
}
void caculate()
{
int size = type.size();
while(max_q != min_q)
{
int sum = 0,min_p;
int mid = (max_q + min_q + 1)/2;//保证每次测试的数比min 大
//printf("%ld %ld %ld\n",max_q,mid,min_q);
for(int i = 0; i < size; i++)
{
min_p = INF;
for(int j = 1; j <= c[i][0].price; j++)
{
if(c[i][j].quality >= mid)
min_p = min(min_p,c[i][j].price);
}
if(min_p == INF)break;
sum += min_p;
}
if(sum > b || min_p == INF)max_q = mid - 1;
else min_q = mid;
//printf("===%ld %ld %ld\n",max_q,mid,min_q);system("pause");
}
printf("%d\n",min_q);
}
int main(int argc, char *argv[])
{
int kase;
scanf("%d",&kase);
while(kase--)
{
scanf("%d%d",&n,&b);
type.clear();
memset(c,0,sizeof(c));
max_q =MIN,min_q = INF;
char name[30],tp[30];
int p,q;
for(int i = 0; i < n; i++)
{
scanf("%s%s%d%d",tp,name,&p,&q);
int id = Id(tp);
component t;
t.price = p;
t.quality = q;
c[id][++c[id][0].price] = t;
min_q = min(min_q,q);
max_q = max(max_q,q);
}
caculate();
}
// system("PAUSE");
return EXIT_SUCCESS;
}