目录
标题写英文Recommendation System会提示含有非法字符。。。
1,题目描述
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
题目大意
写一个简单的推荐算法。用户依次查询商品,算法根据先前查询的商品次数来给出K个推荐,出现频率高的排在前面,若频率相等则id小的排在前面。
知识补充
C++运算符重载
参考菜鸟教程@菜鸟教程【C++ 重载运算符和重载函数】
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
Box operator+(const Box&);
声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:
Box operator+(const Box&, const Box&);
在这里,对象作为参数进行传递,对象的属性使用 this 运算符进行访问,比如:
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
2,思路
1,设计结构体item,并对运算符“<”进行重载,使得商品插入set<item> recom时,直接按照顺序插入:
2,每查询一次商品,便将recom中前K个商品id输出:
3,因为新增了一次对商品的查询,所以需要更新商品在recom中的顺序(若recom中无当前查询的商品,则直接插入即可;若有,则需先删除原先的商品id,将其出现频率加1后,再重新插入recom中,并对fre[id]进行更新;)
3,AC代码
#include<bits/stdc++.h>
using namespace std;
struct item{
int id, fre; //id商品编号 fre购买次数
bool operator < (const item&t)const{ // 大括号前加上const不然会有一堆警告
return this->fre != t.fre ? this->fre>t.fre : this->id<t.id;// !!!t是实体不是指针 所以是.不是->
}
};
int N, K, id, fre[50005]; //fre记录每个商品的访问次数
set<item> recom; //recom记录按照访问次数排序的商品id
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d%d%d", &N, &K, &id);
recom.insert({id, 1});
fre[id]++;
for(int i = 2; i <= N; i++){
scanf("%d", &id);
printf("%d: ", id);
int k = 0;
for(auto it = recom.begin(); it != recom.end() && k < K; it++){
printf("%s%d", it==recom.begin() ? "":" ", it->id);
k++;
}
printf("\n");
auto it = recom.find({id, fre[id]});
if(it != recom.end()) // 若以前查询过此商品
recom.erase(it); // 更新查询次数
recom.insert({id, ++fre[id]}); // !!!前自增
}
return 0;
}
4,解题过程
第一搏
一开始怎么也看不懂题目,,,为什么题目输入给的3开头,输出却是5(顺序是怎么定的???)
突然注意到Note: there is no output for the first item since it is impossible to give any recommendation at the time
于是我把3先去掉,一看顺序果然对上了(菜的我不敢吱声。。。)
于是:
#include<bits/stdc++.h>
using namespace std;
struct node{
int id, fre;
};
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
int N, K, id;
cin>>N>>K;
vector<node> itemFre;
for(int i = 0; i < N; i++){
scanf("%d", &id);
if(i != 0) printf("%d: ", id);
for(int j = 0; j < itemFre.size() && j < K; j++) //输出目前已有的推荐结果
printf("%d%c", itemFre[j].id, (j==itemFre.size()-1 || j==K-1) ? '\n':' ');
int index = 0;
while(index < itemFre.size()){ //定位id在itemFre中的位置
if(itemFre[index].id == id){
itemFre[index].fre++;
break;// !!!不能省
}
else index++;// !!!不能省
}
// if(index == itemFre.size())//之前未查询过此商品
// itemFre.push_back({id, 1});
// else{
// while(index > 0){
// if((itemFre[index].fre > itemFre[index-1].fre) ||
// (itemFre[index].fre == itemFre[index-1].fre && itemFre[index].id < itemFre[index-1].id)){
// swap(itemFre[index], itemFre[index-1]);
// index--;
// }else break;
// }
// }
if(index == itemFre.size()){//之前未查询过此商品 重新给index赋值
itemFre.push_back({id, 1});
index = itemFre.size()-1;
}
while(index > 0){
if((itemFre[index].fre > itemFre[index-1].fre) ||
(itemFre[index].fre == itemFre[index-1].fre && itemFre[index].id < itemFre[index-1].id)){
swap(itemFre[index], itemFre[index-1]);
index--;
}else break;
}
}
return 0;
}
还特地做了优化,,,然而还是不行。。。
之后又想了一些其他方法,比如用pos记录下表,并及时更新,这样就不需要每次遍历itemFre来查找对应商品,,,但实现过程比较复杂,而且本质上并没有提高。
第二搏
请神时间。
网上的大佬们都用的是set+运算符重载,轻松搞定。
然而目前为止我还没用过。。。现学现卖,有一说一,是真的香!