题目大意:你有b块钱,要组装一台电脑,给n个配件,每个配件给出种类,名称,价格,品质。电脑整体水平取决于最差的哪个配件的品质,因此要求最低的品质的配件的品质尽可能的大。输出组装的电脑配件里面最低的品质的最大值。
解题思路:首先我想到的是都买最便宜的,然后有钱就把最差的换的稍微好一点。不断更新。因为每次提升都是把最差的变好,那么就会更新到最大值。更换配件时我们都买最便宜的换掉当前品质最差的即可,那些品质差都舍弃即可,思路比较简单,实现比较麻烦,首先我们用一个优先队列集合保存所有的配件,别且分类,每一个类保存到一个优先队列里,每次取最便宜的,我们用同类的配件去换时,如果这个配件品质低,直接跳过即可,如果品质高,那我们看一下能不能买得起,只要买的起就不用看了,后面的价格都比这个高。我们再用一个优先队列保存当前我们选了的配件,品质最差的优先,每次拿出来的都是品质最低的。更新到最后就时最大值。
还有一种方法是二分,蓝书上的
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <stack>
#include <vector>
#include <string>
#define mem(s) memset(s, 0, sizeof(s))
using namespace std;
struct Acces
{
char name[25];
int pri, qua; //价格和品质
};
struct Cmp1 //重载() 价格小的优先
{
bool operator() (const Acces &a, const Acces &b) const
{
return a.pri > b.pri;
}
};
struct Cmp2// 品质低的优先
{
bool operator() (const Acces &a, const Acces &b) const
{
return a.qua > b.qua;
}
};
map<string, int> ID;
priority_queue<Acces, vector<Acces>, Cmp1> can_choose[10005];//可以取的有哪些
priority_queue<Acces, vector<Acces>, Cmp2> cur_choose;//当前有哪些配件
int main()
{
int t; cin >> t;
int n, b;
char s[30];
Acces a;
while(t--)
{
//初始化
ID.clear();
while(!cur_choose.empty()) cur_choose.pop();
for(int i=0; i<10005; i++)
while(!can_choose[i].empty()) can_choose[i].pop();
scanf("%d%d", &n, &b);
int max_id = 1;//id要从1开始 一开始从零了找了好一会bug,因为下面有个判断是否存在了的, id为零跟不存在一样,无法辨别
for(int i=0; i<n; i++)
{
scanf("%s%s%d%d", a.name, s, &a.pri, &a.qua);
string s(a.name);
if(!ID[s]) ID[s] = max_id++;//给每个种类分配一个ID
can_choose[ ID[s] ].push(a);//将配件分类,分别加到队列里
}
for(int i=1; i<max_id; i++)//每种配件都要最便宜的
{
a = can_choose[i].top();
can_choose[i].pop();
b -= a.pri;
cur_choose.push(a);
}
while(1)
{
a = cur_choose.top();//品质最低的配件
string s(a.name);
int id = ID[s]; //获取这个配件的种类
if(can_choose[id].empty()) break; //这个种类的配件没有了,那最差的一定是这个了
Acces tmp;
int ok = 0;
while(!can_choose[id].empty())
{
tmp = can_choose[id].top();
can_choose[id].pop();
if(tmp.qua <= a.qua) continue; //品质比当前的还低,不考虑
if(b + a.pri >= tmp.pri) //能买的起最便宜的,并且品质更高
{
ok =1;
break;
}
}
if(!ok) break;//没找到
cur_choose.pop();//更新
cur_choose.push(tmp);
b -= tmp.pri - a.pri;
}
a = cur_choose.top();//品质最低的
printf("%d\n",a.qua);
}
return 0;
}
二分法:
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
using namespace std;
int n, b;
int cnt;
struct Acces
{
int pri, que; //价格,品质
};
vector<Acces> A[1005]; //所有配件
map<string, int> ID;
bool cheek(int x) //检查配件品质都x以上时钱够不够
{
int sum = 0;
for(int i=1; i<cnt; i++)
{
int cur = b+1;
for(int j =0; j<A[i].size(); j++)
if(A[i][j].que >= x) cur = min(cur, A[i][j].pri);
if(cur == b+1) return false;
sum += cur;
if(sum > b) return false;
}
return true;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
ID.clear();
for(int i=0; i<1005; i++) A[i].clear();
scanf("%d%d", &n, &b);
char type[30], name[30];
int p, q, max_q = 0;
cnt = 1; // id从1开始
for(int i=0; i<n; i++)
{
scanf("%s%s%d%d", type, name, &p, &q);
string s(type);
if(!ID[s]) ID[s] = cnt++; // 给每个种类分配一个id
if(max_q < q) max_q = q;
A[ ID[s] ].push_back((Acces){p, q});
}
int L = 0, R = max_q;
while(L < R) //二分查找
{
int mid = L + (R-L+1)/2;
if(cheek(mid)) L = mid;
else R = mid-1;
}
printf("%d\n", L);
}
return 0;
}