例题1.12 组装电脑 Assemble UVALive - 3971 模拟或者二分

传送门

题目大意:你有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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值