目錄
標題寫英文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+運算符重載,輕鬆搞定。
然而目前爲止我還沒用過。。。現學現賣,有一說一,是真的香!