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:
- 用一个数组:cont[maxn] 记录每个Query的次数,一个vector: rankList记录当前的查询Q次数排序
- 每次输入一个查询。先判断它是否在rankList里,若不在,将其加入
- 对rankList进行下标排序(rankList里存放的是问题Qi,通过cont[Qi]就可以找到Qi对应的查询次数,以此来排序)
- 若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;
}