题目:
给定电脑的n(n<1000)个配件,每个配件有类型,名字(没用的信息),价格和品质因子。要求每种类型的配件各买一个用于组装电脑,总价格不超过b元。求所有可能的方案中品质因子最差的那个配件的品质因子最大能是多少。
分析:
看着这数据,觉得暴力也可做,枚举每个品质因子,找出满足要求的最大的。但如果数据大一点,就不能这么暴力了,就要二分答案去找最优解了。
具体实现,就是把每种类型的配件都保存到一个vector中,买的时候从这里面选择一个品质因子比最小的要大的品质因子且价格最低的配件,然后把所有的加起来,判断一下是不是<=b就好。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<string>
using namespace std;
typedef pair<int,int>pii;
#define pb push_back
#define mpi make_pair
map<string,int>mp; //每中类型对应一个保存这种类型配件的vector
vector<pii>vec[1001]; //保存每种类型的配件
int b,n,cnt;
bool check(int q)
{
vector<pii>::iterator it;
int sum=0;
for(int i=0;i<cnt;i++){
it=lower_bound(vec[i].begin(),vec[i].end(),pii(q,0));
if(it==vec[i].end())return 0;
int minn=1e9;
for(;it!=vec[i].end();it++)
if(it->second<minn)minn=it->second;
sum+=minn;
}
if(sum<=b)return 1;
return 0;
}
int main()
{
//freopen("f.txt","r",stdin);
int T;scanf("%d",&T);
while(T--){
for(int i=0;i<cnt;i++)vec[i].clear();
mp.clear();
cnt=0;
vector<int>a;//保存出现过的品质因子
map<int,bool>ma; //判重,出现过的品质因子就不要再加到a中了
scanf("%d%d",&n,&b);
string s1,s2; int p,q;
for(int i=0;i<n;i++){
cin>>s1>>s2;
scanf("%d%d",&p,&q);
if(mp.count(s1)){
vec[mp[s1]].pb(mpi(q,p));
}
else{
mp[s1]=cnt++;
vec[mp[s1]].pb(mpi(q,p));
}
if(!ma.count(q))a.pb(q),ma[q]=1;
}
for(int i=0;i<cnt;i++)sort(vec[i].begin(),vec[i].end());
int l=0,r=a.size()-1;
sort(a.begin(),a.end());
while(l<r){
int m=(l+r)>>1;
if(check(a[m]))l=m+1;
else r=m-1;
}
if(l<a.size()&&check(a[l])) //因为二分,不确定是不是l是最优解,有可能l不是。所以再判断一下
printf("%d
",a[l]);
else if(check(a[l-1]))
printf("%d
",a[l-1]);
}
return 0;
}