1129 Recommendation System (25 point(s))
Recommendation system predicts the preference that a user would give to an item. Now you are asked to program a very simple recommendation system that rates the user's preference by the number of times that an item has been accessed by this user.
Input Specification:
Each input file contains one test case. For each test case, the first line contains two positive integers: N (≤ 50,000), the total number of queries, and K (≤ 10), the maximum number of recommendations the system must show to the user. Then given in the second line are the indices of items that the user is accessing -- for the sake of simplicity, all the items are indexed from 1 to N. All the numbers in a line are separated by a space.
Output Specification:
For each case, process the queries one by one. Output the recommendations for each query in a line in the format:
query: rec[1] rec[2] ... rec[K]
where query
is the item that the user is accessing, and rec[i]
(i
=1, ... K) is the i
-th item that the system recommends to the user. The first K items that have been accessed most frequently are supposed to be recommended in non-increasing order of their frequencies. If there is a tie, the items will be ordered by their indices in increasing order.
Note: there is no output for the first item since it is impossible to give any recommendation at the time. It is guaranteed to have the output for at least one query.
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
考察点:STL set的理解和灵活使用
题意:
用户每想购买一件商品,就向他推荐K个商品,这K个商品从他从前的购买过的商品中按照购买次数从高到低的顺序选择K个,如果有购买次数相同的,就按照商品的编号从小到大排序。
心路历程:
好好写一下做这道题的心路历程。首先,这道题的输出是随着查询的次数而增长的,对于每一次查询,要基于购买次数和下标进行排序,可想而知,如果每一次查询都重新排序,时间复杂度必然太高。需要注意,每一次查询我们还需要修改购买次数,而排序后我们不能够通过下标再访问了,那还需要基于线性结构的查找,这也是很复杂的。
显然,我们需要寻找一种数据结构来维护这个排序,利用红黑树的set自动排序,我们可以对结构体(包括下标和访问次数)重载运算符<来实现。这个方法我在做题的时候也是想到了,但是问题仍然是如何去修改set中的元素呢?因为我们不能够只通过商品下标来查找,于是我们需要额外维护一个数组记录每个商品的访问次数,仅仅是为了我们对set的查询。
似乎一切迎刃而解了,但是set的元素并不能修改,怎么办呢?先删除后插入。
这道题真的学了很多东西,花了一个多小时,参考了大神的做法(https://blog.csdn.net/richenyunqi/article/details/80173656),对set的理解更加深入了,如何合理高效地利用轮子,真的是机考中的重中之重!
#include<iostream>
#include<map>
#include<algorithm>
#include<set>
using namespace std;
const int MAX = 5e4+7;
struct item{
int id;int cnt;
item(int i,int c):id(i),cnt(c){}
bool operator < (const item &other) const{
if(cnt!=other.cnt) return cnt>other.cnt;
else return id<other.id;
}
};
set<item> s;
int itemCount[MAX]={0};
int main(void){
int N,K,a;cin>>N>>K;
for(int i=0;i<N;i++){
cin>>a;
if(i>0){
cout<<a<<":";
int output = 0;
for(set<item>::iterator i=s.begin();i!=s.end()&&output<K;i++){
cout<<" "<<(*i).id;
output++;
}
cout<<endl;
}
set<item>::iterator it = s.find(item(a,itemCount[a]));//寻找在set的红黑树中是否已经有这一项
itemCount[a]++;
if(it!=s.end()){//如果有
s.erase(it);// 删除后再插入达到修改的目的
s.insert(item(a,itemCount[a]));
}else{//没有找到
s.insert(item(a,itemCount[a]));
}
}
return 0;
}