zoukankan      html  css  js  c++  java
  • CCF 201909-4 推荐系统

    CCF 201909-4 推荐系统

    试题编号: 201909-4
    试题名称: 推荐系统
    时间限制: 5.0s
    内存限制: 512.0MB
    问题描述:


    算法设计

      由于我们需要选出得分最大的K件商品,得出相同的先按类号从小到大排序,再按编号从小到大排序。那么我们可以将所有商品放入到一个set变量bbt中进行自动排序。另外,同类商品编号必然不同,不同类商品编号可能相同,所以我们可以用类号+编号来唯一标识一件商品。由于商品的编号在10^9 以内,而类号在以内,我们可以用类号∗109+编号 类号*10^9+编号类号∗10 ^9+编号来作为一件商品唯一的id,显然每件商品和其id是一一对应的。这样的id可以用long long类型存储,且按id从小到大排序就相当于题目要求的“先按类号从小到大排序,再按编号从小到大排序”的排序原则。如果我们得到一件商品的id,那么这件商品的类号=id/10^9,编号=id%10^9 。

      于是我们可以定义一个商品类dat,其中定义两个成员变量:id和score。为了方便set排序,需要在类内重载<运算符,保证商品先按得分从大到小排序,再按id从小到大排序。但是这又需要考虑另一个问题,题目中需要对商品进行添加和删除,添加和删除操作都是通过商品的id来操作的,我们显然无法在set中我们需要给出id和score两个变量才能查找到一件商品,而无法只通过商品的id查找到相应的商品。怎么办呢?我们可以另外定义一个unordered_map变量um,键存储商品的id,值存储指向这件商品在set中的位置的迭代器。还记得set中进行插入的insert函数吗?其实这个函数是有返回值的,只不过我们不常用。它的返回值是一个pair,first成员就是指向新插入的元素在set中位置的迭代器,second成员是一个bool表示这次插入操作是否成功。于是我们在向set中插入商品时可以直接通过代码um[a] = bbt.insert(dat(a, score)).first;完成um和bbt的同步更新。进行删除时,我们先通过um找到商品在set中的迭代器,然后利用set的erase函数进行删除,另外别忘了同步对um中的对应元素也进行删除就可以了。

      然后是打印操作,我们可以定义一个变量k存储要选出的最多商品总数,定义一个数组变量K存储每类商品被选中的最多件数,定义一个二位数组变量ans存储每类商品要输出的编号。遍历整个set,假设当前遍历到的商品所属类别为t,而ans[t][0]< K[t],表示当前类别还没有选满,则将当前商品的编号加入到ans[t][]中,另外令变量k递减1,判断k是否变为了0,如果k变为了0,表示商品总数已选够,即可直接结束遍历。

    最后,题目中要求,同类商品的编号从小到大输出,需要对ans中每类商品编号排序再输出即可。

      然而60分之后的数据有问题,如要获得满分,请注释掉第55行用来对要输出的商品进行排序的代码

    #pragma GCC optimize(3,"Ofast","inline")
    #include<set>
    #include<vector>
    #include<stdio.h>
    #include<tr1/unordered_map>
    using namespace std;
    using namespace tr1;
    typedef long long ll;
    const ll mul=1e9;
    const int M=55;
    const int Kn=105;
    struct dat{
        ll id;int s;
        dat(ll id=0,int s=0):id(id),s(s){}
        bool operator <(const dat &c) const{
            return s!=c.s?s>c.s:id<c.id;
        }
    };
    set<dat>bbt; unordered_map<ll,set<dat>::iterator>um;
    int K[M],ans[M][Kn];
    int main(){
        int n,m,cas,opt,t,id,s,k;
        scanf("%d%d",&m,&n);
        for(int i=0;i<n;i++){
            scanf("%d%d",&id,&s);
            for(int j=0;j<m;j++){
                ll a=j*mul+id;
                um[a]=bbt.insert(dat(a,s)).first; 
            }
        }
        for(scanf("%d",&cas);cas--;){
            scanf("%d",&opt);
            if(opt==1){
                scanf("%d%d%d",&t,&id,&s);
                ll a=t*mul+id;
                um[a]=bbt.insert(dat(a,s)).first;
            }
            else if(opt==2){
                scanf("%d%d",&t,&id);
                ll a=t*mul+id;
                bbt.erase(um[a]);um.erase(a);
            }
            else{
                scanf("%d",&k);
                for(int i=0;i<m;i++) scanf("%d",&K[i]),ans[i][0]=0;
                for(auto &i:bbt){
                    t=i.id/mul;
                    if(ans[t][0]<K[t]){
                        ans[t][++ans[t][0]]=i.id%mul;
                        if(!--k) break;
                    }
                }
                for(int i=0;i<m;i++){
                    if(!ans[i][0]){puts("-1");continue;}
    //                sort(ans[i]+1,ans[i]+ans[0]+1)''
                    for(int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
                    puts("");
                }
            }
        }
        return 0;
    }

    ----------------------------------------------------------------------------------------------------------------------------

    以上是来自网路的做法,以下是来自本人的(原创)做法

    ----------------------------------------------------------------------------------------------------------------------------

     其实大同小异。当然,我的做法在常数上效率更高,不然,我也没有必要讲他了。

    /*
    建立一个set群:bst[M]。bst[i]的表示维护第i类商品的set
    题目保证:任意时刻,同类的任意两个商品的编号各不相同 
    所以可以这样哈希映射 ha[当前类][该商品id]-->该商品得分,
    插入:在当前类的set中插入dat(该商品得分,该商品id) 
    删除:在当前类的set中删除dat(ha[当前类][该商品id]即该商品得分,该商品id)  
        因为set删除要么使用迭代器,要么使用无重(包含各项信息的)键值 
    查询: 1、if(sum<=K) 只需将所有bst[i]的信息排序输出
           2、否则,将所有bst[i]的前K大输出。具体操作如下:
               <1>首先将所有bst[i]的最大扔到堆q中,同时在所有set[i]中删除该值.
               <2>将堆顶元素x弹出,并将元素x所属的bst[j]的当前最大y扔到堆q中,同时在set[j]中删除y.
               <3>重复<2>K次 
    */
    #include<set>
    #include<queue>
    #include<cstdio>
    #include<algorithm>
    #include<tr1/unordered_map>
    #include<iostream>
    #include<algorithm>
    #define debug(x) cerr<<#x<<" "<<x<<endl;
    using namespace std;
    using namespace std::tr1;
    const int N=1e5+5;
    const int M=50+5;
    const int Kn=100+5;
    int n,m,as,sum,k[M];pair<int,int>vp[N];
    unordered_map<int,int>ha[M];
    int ans[M][Kn];
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    } 
    struct dat{
        int v,id;
        dat(int _v=0,int _id=0):v(_v),id(_id){}
        bool operator <(const dat &a)const{
            return v!=a.v?v>a.v:id<a.id;
        }
    };
    struct add{
        dat mes;int typ;
        add(dat _mes=0,int _typ=0):mes(_mes),typ(_typ){}
        bool operator <(const add &a)const{
            return mes.v==a.mes.v?typ>a.typ:mes.v<a.mes.v;
        }
    };
    typedef set<dat> bbt;
    bbt bst[M];
    bbt::iterator it[M],ed[M];
    int cnt;
    int main(){
        m=read();n=read();
        for(int i=1,x,y;i<=n;i++) x=read(),y=read(),vp[i]=make_pair(y,x);
        #define x first
        #define y second
        for(int i=0;i<m;i++){
            for(int j=1;j<=n;j++){
                bst[i].insert(dat(vp[j].x,vp[j].y));
                ha[i][vp[j].y]=vp[j].x;
            }
        }
        #undef x
        #undef y
        int op,tpy,com,sco,K,t;
        for(as=read();as--;){
            op=read();
            if(op==1){
                tpy=read();com=read();sco=read();
                bst[tpy].insert(dat(sco,com));
                ha[tpy][com]=sco;
            }
            if(op==2){
                tpy=read();com=read();
                if(t=ha[tpy][com]) bst[tpy].erase(dat(t,com)),ha[tpy][com]=0; 
            }
            if(op==3){
                K=read();sum=0;
                for(int i=0;i<m;i++) k[i]=read(),sum+=k[i];
                for(int i=0;i<m;i++) it[i]=bst[i].begin(),ed[i]=bst[i].end();
                if(sum<=K){
                    for(int i=0;i<m;i++) ans[i][0]=0;
                    for(int i=0;i<m;i++){
                        for(;k[i];k[i]--){
                            if(it[i]==ed[i]) break;
                            ans[i][++ans[i][0]]=it[i]++->id;
                        }
                        if(!ans[i][0]){puts("-1");continue;}
    //                    sort(ans[i]+1,ans[i]+ans[i][0]+1);
                        for(int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
                        puts("");
                    }
                }
                else{
                    priority_queue<add> q;int cat=0;
                    for(int i=0;i<m;i++) if(it[i]!=ed[i]) q.push(add(*it[i]++,i));
                    for(int i=0;i<m;i++) ans[i][0]=0;
                    while(!q.empty()){
                        add now=q.top();q.pop();
                        #define typ now.typ
                        #define com now.mes.id
                         if(k[typ]>0){
                            ans[typ][++ans[typ][0]]=com;
                            ++cat; 
                            if(cat==K) break;
                            k[typ]--;
                            if(k[typ]>0&&it[tpy]!=ed[tpy]) q.push(add(*it[typ]++,typ));
                        }
                        #undef typ
                        #undef com
                    }
                    for(int i=0;i<m;i++){
                        if(!ans[i][0]){puts("-1");continue;}
    //                    sort(ans[i]+1,ans[i]+ans[i][0]+1);
                        for(int j=1;j<=ans[i][0];j++) printf("%d ",ans[i][j]);
                        puts("");
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    XI.spring的点点滴滴--IObjectFactoryPostProcessor(工厂后处理器)
    Ⅹ.spring的点点滴滴--IObjectPostProcessor(对象后处理器)
    Ⅸ.spring的点点滴滴--IObjectFactory与IFactoryObject的杂谈
    Ⅷ.spring的点点滴滴--抽象对象和子对象
    Ⅶ.spring的点点滴滴--自定义对象行为
    Ⅵ.spring的点点滴滴--自定义类型转换器
    Ⅴ.spring的点点滴滴--引用其他对象或类型的成员
    Ⅳspring的点点滴滴--方法和事件
    Ⅲ.spring的点点滴滴--赋值
    Ⅱ.spring的点点滴滴--对象
  • 原文地址:https://www.cnblogs.com/shenben/p/11985009.html
Copyright © 2011-2022 走看看