组装电脑 LA 3971 二分答案

题目:
给定电脑的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\n",a[l]);
        else if(check(a[l-1]))
            printf("%d\n",a[l-1]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值