CCF 2019-09-4 推荐系统 100分

题意

题目中给你m类商品每一类商品都会编号不同的n个商品
要你在某种情况下推荐出合适(分数最高)的商品
有3种操作

  1. 输入为1开头的增加操作,1后跟着3个数字分别为商品类别,商品编号,商品分数。
  2. 输入为2开头的删除操作,2后跟着2个数字分别为商品类别,商品编号。
  3. 输入为3开头的推荐操作,3后跟着m+1个数字其中第一个数字代表本次从所有商品中选出最大的商品数(可以不达到但不能超过),接下来m个数为每一类商品中最大选出的商品数。要求输出每类商品的推荐编号同类商品按从小到大的顺序排列。

商品选择时的比较逻辑

  • 先选分数最高的
  • 如果类别不同,选择类别编号最小的
  • 如果类别相同,选择商品编号最小的

思路

采用set保存一个{类别,编号,分数}类,该类自己实现<运算符函数就可以解题,但是这种做法却有一个难点,删除操作时无法删除因为删除操作只给出了商品类别,商品编号,无从得知分数的信息。
解决办法:再设立一个{类别,编号}到{分数}的映射
100分选择(哈希永远滴神)
set<>
unordered_map<>
80分选择 超时(平衡树暂时的神)
set<>
map<>
20分选择
vector<> + sort()
在这里插入图片描述

代码



#include <iostream>
#include <map>
#include <unordered_map>
#include <set>
#include <vector>
#include <fstream>
#include <sstream>
#include <algorithm>
using namespace std;
int m, n, op_num;
vector<vector<int>> ops;
class Commodity {
public:
	int type;
	int number;
	int score;
	Commodity(const int& a, const int& b, const int& c) :type(a), number(b), score(c) {  }
	bool operator <(const Commodity& b)const {
		if (score != b.score)
			return score > b.score;
		else if (type != b.type)
			return  type < b.type;
		else
			return number < b.number;
	}
};
class pair_hash {
public:
	template<typename T1, typename T2>
	size_t operator()(const pair<T1, T2>& a)const {
		return hash<T1>{}(a.first) ^ hash<T2>{}(a.second);
	}
	/*size_t operator()(const pair<int, int>& a)const {
		return hash<int>{}(a.first) ^ hash<int>()(a.second);
	}*/
};
unordered_map<pair<int, int>, int, pair_hash> maps;
//map<pair<int, int>, int> maps;//80分警告
set<Commodity> cs;


void excuteOps() {
	for (const auto& op : ops) {

		switch (op[0])
		{
		case 1:
			cs.insert({ op[1],op[2],op[3] });
			maps[{op[1], op[2]}] = op[3];
			break;
		case 2:
			cs.erase({ op[1],op[2],maps[{op[1],op[2]}] });
			maps.erase({ op[1], op[2] });
			break;
		case 3:
			int k = op[1];
			vector<int> counts(op.begin() + 2, op.end());//计数m个类中每个类选出的个数
			vector<vector<int>> resv;//保存结果
			resv.resize(m);
			for (const auto& x : cs) {
				if (!k)break;
				else if (counts[x.type]) {
					resv[x.type].push_back(x.number);
					--counts[x.type];
					--k;
				}
			}
			for (auto& x : resv) {
				if (x.size() == 0)cout << -1;
				//sort(x.begin(), x.end());//同类从小到大输出,疑问:按道理应该是要有的但不知为什么只要加了一句就只有60分
				for (const auto& xx : x) {
					cout << xx << ' ';
				}
				cout << endl;
			}
			break;
		}
	}
}
//#define DEBUG

int main() {
#ifdef DEBUG
	fstream cin("input.txt");
#endif // DEBUG

	cin >> m >> n;
	for (int i = 0; i < n; ++i) {
		int id, score;
		cin >> id >> score;
		for (int j = 0; j < m; ++j) {
			maps[{j, id}] = score;
			cs.insert({ j,id,score });
		}

	}
	cin >> op_num;
	ops.resize(op_num);
	cin.get();//去回车
	for (int i = 0; i < op_num; ++i) {
		stringstream strs;
		string str;
		int temp;
		getline(cin, str);
		strs << str;
		while (strs >> temp)
			ops[i].push_back(temp);
	}
	excuteOps();
}

2 3
1 3
2 2
3 1
8
3 100 1 1
1 0 4 3
1 0 5 1
3 10 2 2
3 10 1 1
2 0 1
3 2 1 1
3 1 1 1
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值