CCF认证 201909-4 《推荐系统》

在这里插入图片描述

题目分析

1、m类商品,每类商品初始为n个

2、推荐商品总阈值K,各类商品也有阈值k

3、商品清单,可以 【增加】、【删除】,【输出】

4、输出每类商品,没有的话-1,有的话按照编号由小到大顺序输出

解题策略

1、先看测试点

在这里插入图片描述
一般109就是题目暗示用int,不能开数组散列
首先想到的是使用priority_queue优先级队列,队列中的元素自动有序(满足这个条件的还有set集合

然后再考虑是m个优先级队列还是一个优先级队列?

从三个方面(增加,删除,输出)分析。

(1)【增加】,type,commodity,score多个队列和一个队列没什么差别,set也可以。

(2)【删除】,只给出type,commodity,从优先级队列中随机删除某个元素是非常困难的,因为队列不支持随机访问。------------- 具有相同有序性质的容器set,支持随机访问,删除容器内的时间复杂度为logN,N为容器内的元素数量,set.erase(value),需要知道score。score和<type,commodity>相关。需要实现<type,commodity>到score的映射,不能开二维数组,commodity的阈值为109,可以使用map或者unordered_map来实现。

map<int,bool> mg[55]
unordered_map<int,bool> mg[55]

(3)【输出】,所有商品一起参与排序,根据输出要求使用vector<int> out[55]来存储推荐的商品。

如果是多个队列或者集合?每确定一个商品,需要遍历一遍m个队列或者集合。而单个队列则不需要。
每确定一个商品,那么这个商品就不能参与之后的比较,如果是队列的话,因为不支持随机访问,必须出队列,最终输出后再push进来,太麻烦啦。set可以弥补这个缺点。再考虑到多个set需要记录当前type商品数到了什么位置,单个set不需要。

综合以上考虑,确定使用单个set来存储商品,并且可以删除操作可以物理上删除,也可以直接用一个标志位来表示就行了,更简单快速一点。

60分找不到错误,到网上一搜发现是测试用例的问题,不需要对out[i]进行排序,直接按顺序输出。😔

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <set>
#include <vector>
using namespace std;
int m,n;
struct goods{ //商品结构体,定义排列序列
    int type;
    int ID;
    int score;
    goods(int a,int b,int c)
    {
        type = a;
        ID = b;
        score = c;
    }
    friend bool operator <(goods a,goods b) //重载<,对set序列进行定义
    {
        if(a.score == b.score)
        {
            if(a.type == b.type)
                return a.ID < b.ID;
            else
                return a.type < b.type;
        } else
            return a.score > b.score;
    }
};
set<goods> sg; //使用一个集合足够
unordered_map<int,bool> isDelete[55]; //删除<type,commodity>
vector<int> out[55]; //输出统计
int main()
{
    scanf("%d %d",&m,&n);
    int i,j;
    int a,b,c;
    for(i=0;i<n;i++) //输入初始化数据
    {
        scanf("%d %d",&b,&c);
        for(j=0;j<m;j++)
            sg.insert(goods(j,b,c));
    }

    int op,index;
    scanf("%d",&op);
    while(op--)
    {
        scanf("%d",&index);
        if(index == 1) //增加
        {
            scanf("%d %d %d",&a,&b,&c);
            sg.insert(goods(a,b,c));
        } else if(index == 2) //删除
        {
            scanf("%d %d",&a,&b);
            isDelete[a][b]=true;      // 标记商品类型a,商品号b为已删除
        } else
        {
            int K,ks[55];     //最大数量
            scanf("%d",&K);
            for(i=0;i<m;i++)
            {
                scanf("%d",&ks[i]);
                out[i].clear(); //完成对out的重置
            }

            set<goods>::iterator it;
            for(it=sg.begin();it!=sg.end();it++)
            {
                a = it->type;
                b = it->ID;
                c = it->score;
                if( ks[a]>0 && !isDelete[a][b])
                {
                    out[a].push_back(b);
                    ks[a]--;
                    K--;
                }
                for(i=0;i<m;i++)
                    if(ks[i] > 0)
                        break;
                if(i==m || K==0) // 总数K 或者 每类商品都到达阈值
                    break;       // 跳出循环
            }
            // 开始输出
            for(i=0;i<m;i++)
            {
            //    sort(out[i].begin(),out[i].end()); // 对商品序号进行排序
                if(out[i].empty())
                    printf("-1\n");
                for(j=0;j<out[i].size();j++)
                    printf("%d%c",out[i][j],j==out[i].size()-1?'\n':' ');
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值