PAT A1129 Recommendation System (25 分)排序 优先队列

60 篇文章 0 订阅

    题目大意:设计一个推荐系统。用户有N次输入,每次输入的是一件商品的 id (1~N),要求从第2次输入开始推荐,即列出用户之前搜索次数最多的K件商品(不足K件没关系,但是不能超过K件)。对于搜索次数相同的,按照 id 排序。N <= 50000, K <= 10。

    首先设置结构体 query记录次数和 id,然后就是根据用户每次的输入来推荐。问题主要是对于 N = 50000的量级,不可能每次都全部排序然后得到最大的 K 个,否则肯定超时。因此,必须要维护一个长度最大为 K 的 vector,用来保存 K个最大的 query。然后分三种情况:①当前输入id 不在 v内,v的长度小于K,直接加入v。② 当前id在v内,v的长度等于K, 比较当前id和v中最小元素的大小,决定是否要增删。③ 当前id在v内,更新当前id对应的计数值。最后,对v排序。由于v的长度不超过10,即使进行50000次排序,也不会超时。设置hashTable用于记录id是否在v中。

AC代码:

#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;

struct query
{
    int cnt;
    int index;
    bool operator <(const query &other)
    {
        if(this->cnt != other.cnt) return this->cnt > other.cnt;
        else return this->index < other.index;
    }
};

int main()
{
    int N, K;
    scanf("%d%d", &N, &K);
    vector<bool> inq(N+1, 0);
    vector<int> cnt(N+1, 0);
    vector<query> v;
    for (int i = 0; i < N; ++i)
    {
        query now;
        scanf("%d", &now.index);
        now.cnt = ++cnt[now.index];
        if(i > 0)
        {
            printf("%d:", now.index);
            for (int j = 0; j < v.size(); ++j)
                printf(" %d", v[j].index);
            printf("\n");
        }
        if(!inq[now.index] && v.size() < K)
        {
            v.push_back(now);
            inq[now.index] = true;
        }
        else if(!inq[now.index] && v.size() == K)
        {
            if(now.cnt > v[K-1].cnt || (now.cnt == v[K-1].cnt && now.index < v[K-1].index))
            {
                inq[v[K-1].index] = false;
                v.pop_back();
                v.push_back(now);
                inq[now.index] = true;
            }
        }
        else if(inq[now.index])
        {
            for (int j = 0; j < v.size(); ++j)
                if(v[j].index == now.index) v[j] = now;
        }
        sort(v.begin(), v.end());
    }
    return 0;
}


    事实上一开始没有想到用vector,而是想用优先队列来实现,维护一个最大长度为K的优先队列q,队首始终是最小的那个元素。思想基本上一样,分三种情况,①当前输入不在q内,q的长度小于K,那么加入。② 当前输入不在q内,q的长度等于K,那么比较当前输入和队首元素的关系,决定是否要增删。③ 当前输入在q内,那么更新q的内容。

    但由于优先队列不能直接操作元素,只能不断pop,所以代码写起来更冗长。同时注意优先队列重载小于运算符要写成全局函数,否则无法编译。

优先队列AC代码:

#include <vector>
#include <cstdio>
#include <queue>

using namespace std;

struct query
{
    int cnt;
    int index;
};

bool operator<(query a, query b)
{
    if(a.cnt != b.cnt) return a.cnt > b.cnt;
    else return a.index < b.index;
}

int main()
{
    int N, K;
    scanf("%d%d", &N, &K);
    vector<bool> inq(N+1, 0);
    vector<int> cnt(N+1, 0);
    priority_queue<query> q;
    for (int i = 0; i < N; ++i)
    {
        query now;
        scanf("%d", &now.index);
        now.cnt = ++cnt[now.index];
        if(i > 0)
        {
            printf("%d:", now.index);
            priority_queue<query> tmp = q;
            vector<int> v;
            while(!tmp.empty())
            {
                query t = tmp.top();
                tmp.pop();
                v.push_back(t.index);
            }
            for (int j = v.size() - 1; j >= 0; --j)
                printf(" %d", v[j]);
            printf("\n");
        }
        if(!inq[now.index] && q.size() < K)
        {
            q.push(now);
            inq[now.index] = true;
        }
        else if(!inq[now.index] && q.size() == K)
        {
            query t = q.top();
            if(now.cnt > t.cnt || (now.cnt == t.cnt && now.index < t.index))
            {
                q.pop();
                inq[t.index] = false;
                q.push(now);
                inq[now.index] = true;
            }
        }
        else if(inq[now.index])
        {
            priority_queue<query> tmp;
            while(!q.empty())
            {
                query t = q.top();
                q.pop();
                if(t.index != now.index) tmp.push(t);
            }
            tmp.push(now);
            q = tmp;
        }
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值