PAT A1129 Recommendation System

PAT A1129 Recommendation System

在这里插入图片描述

Sample Input:

12 3
3 5 7 5 5 3 2 1 8 3 8 12

Sample Output:

5: 3
7: 3 5
5: 3 5 7
5: 5 3 7
3: 5 3 7
2: 5 3 7
1: 5 3 2
8: 5 3 1
3: 5 3 1
8: 3 5 1
12: 3 5 8
  • 思路 1:
  1. 用一个数组:cont[maxn] 记录每个Query的次数,一个vector: rankList记录当前的查询Q次数排序
  2. 每次输入一个查询。先判断它是否在rankList里,若不在,将其加入
  3. 对rankList进行下标排序(rankList里存放的是问题Qi,通过cont[Qi]就可以找到Qi对应的查询次数,以此来排序)
  4. 若rankList不空,从头到尾输出(够k个输出前k个,不过输出到头)
    对于2:需只保留前k名,否则会超时!做法是,当查询问题的个数比k大时,与rankList最后一名做比较,判断是否可以踢下最后一名(末位淘汰)
  • code 1:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500010;
int cont[maxn];	//com[i]存的是查询问题的id(不重复) 
vector<int> rankList;
bool cmp(int idex1, int idex2){
	return cont[idex1] != cont[idex2] ? cont[idex1] > cont[idex2] : idex1 < idex2;
}
int main(){
	int n, k, q;
	scanf("%d %d", &n, &k);
	memset(cont, 0, sizeof(cont));
	for(int i = 0; i < n; ++i){
		scanf("%d", &q);
		if(rankList.size() > 0){
			printf("%d:", q);
			for(int j = 0; j < k && j < rankList.size(); ++j)
				printf(" %d", rankList[j]);
			printf("\n");
		}
		cont[q]++;	
		if(find(rankList.begin(), rankList.end(), q) == rankList.end()){
			if(rankList.size() < k){
				rankList.push_back(q);
			}
			else if(cmp(q, rankList[k-1])){
				rankList[k-1] = q;
			}
		} 
		sort(rankList.begin(), rankList.end(), cmp);
	}
	return 0;
} 
  • T2 code: 哈希表inq,实现查询是否在队中
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50010;
int cnt_num[maxn];
vector<int> v;

bool cmp(int a, int b){
	return cnt_num[a] != cnt_num[b] ? cnt_num[a] > cnt_num[b] : a < b;
}
//bool Find(int x, int k){
//	if(v.size() == 0) return false;
//	for(int i = 0; i < k; ++i) if(v[i] == x) return true;
//	return false;
//}
map<int, bool> inq;
void Push(int x, int k){
	if(inq[x] == false){
		if(v.size() < k){
			v.push_back(x);
			inq[x] = true;
		}else if(cmp(x, v[k-1])){
			inq[v[k-1]] = false;
			inq[x] = true; 
			v[k-1] = x;	
		}	
	}
	sort(v.begin(), v.end(), cmp);
}
int main(){
	int n, m, tmp;
	scanf("%d %d", &n, &m);
	for(int i = 0; i < n; ++i){
		scanf("%d", &tmp);
		if(i != 0){
			printf("%d:", tmp);
			for(int j = 0; j < v.size() && j < m; ++j){
				printf(" %d", v[j]);
			}
			printf("\n");
		}
		cnt_num[tmp]++;
		Push(tmp, m);
	}
	return 0;
} 
  • 思路 2:
    学习柳神的重载set的<,直接用set实现自动排序

  • code 2:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500010;
int cont[maxn];
struct Query{
	int qid, times;
	bool operator < (const Query &q) const{
		return (times != q.times) ? times > q.times : qid < q.qid;
	}
};
int main(){
	int n, m, tmpq;
	scanf("%d %d", &n, &m); 
	set<Query> seq;
	for(int i = 0; i < n; ++i){
		scanf("%d", &tmpq);
		if(i > 0){
			printf("%d:", tmpq);
			int cnt = 0;
			for(auto it = seq.begin(); it != seq.end() && cnt < m; ++it){
				printf(" %d", it->qid);	//!!!Wrong 1:必须用->不能用. 
				cnt++;
			}
			printf("\n");
		}
		auto it = seq.find(Query{tmpq, cont[tmpq]});
		if(it != seq.end()) seq.erase(it);
		cont[tmpq]++;
		seq.insert(Query{tmpq, cont[tmpq]});
	}
	return 0;
} 
  • 自定义set的排序规则,写一个排序类:

【注意】:重写后会按照新规则排序,如果每次插入之前,不提前把已经存在于set中的相同元素删除,会失去去重功能,这和set的实现原理有关(红黑树),进入set的只是一个副本,改动后(cnt_num[tmp]++)再插入会和set中已经插入的元素冲突,可能不认为是同一个?我猜的

  • T2 code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50010;
int cnt_num[maxn];
struct cmp{
	bool operator () (const int & a, const int & b) const {
		return cnt_num[a] != cnt_num[b] ? cnt_num[a] > cnt_num[b] : a < b;
	}
};
set<int, cmp> st;
int main(){
	int n, m, tmp;
	scanf("%d %d", &n, &m);
	for(int i = 0; i < n; ++i){
		scanf("%d", &tmp);
		if(i != 0){
			printf("%d:", tmp);
			auto it = st.begin();
			for(int j = 0; j < st.size() && j < m; ++j, ++it){
				printf(" %d", *it);
			}
			printf("\n");
		}
		if(st.find(tmp) != st.end()) st.erase(tmp);
		cnt_num[tmp]++;
		st.insert(tmp);		
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值