CCF201909-4推荐系统

原题链接

http://118.190.20.162/view.page?gpid=T91
是2019年9月份的第四道真题。

解题思路

又是一道题目又臭又长的题,当然,还是要耐着性子看。我这么粗心的人竟然过了太感动了。细心一些,没什么算法的技巧。大概就是熟练使用STL吧。

输入部分

第一行:m类商品,初始时每类商品有n个。
1-m行:每一类商品中编号为id的商品得分都是score分(就是初始时每一类商品中编号相同的商品得分都相同)
第m+1行:操作次数num
m+2~m+1+num行:随机的三种操作指令

输出部分

假设num次操作中有k次查询操作(那些以3开头的指令),那么就应该输出m*k行。
也就是每遇到一个查询指令,都要输出m行,每一行row代表第row类商品中应该选择哪些编号的商品去展示。
例如输入中以3开头的指令只有一条,总共有m=2类商品,那么就应该输出2行。比如:
1 3 //代表第一类商品选择编号为1和3的商品展示
2 //第二类中选择编号为2的商品去展示

商品怎么存

每一个商品都有类别号,编号以及得分情况,所以容易想到用结构体存每一件商品的信息。

struct node{
	int score; //分数 
	int type; //类别 
	int id;//编号 
}; 

一件商品存好了,那所有商品用什么数据结构存?我用的是STL中的优先队列。
设置好优先级的话查询操作就很方便O(1)的复杂度,添加同样容易,主要就是删除怎么处理,因为没想出更好的方法,我就用了很笨的方法,建一个vector invalid; 遇到2号指令(2开头的是删除指令),就将这个商品push_back进invalid数组,然后写一个bool isValid(node n){};函数,查询时先判断该商品是否无效(在invalid数组中),无效就跳过就行了。

vector<node> invalid;//存放已经被删除的结点 
bool isValid(node n){
	int num = invalid.size();
	for(int i=0; i<num; i++){
		if(n.id==invalid[i].id&&n.type==invalid[i].type)
			return false;
	}
	return true;
}

怎么选商品

题目中写的很明白,根据三种情况排序,分最高的先输出,分一样类号小的先输出,类号也一样编号小的先输出。那就可以写出排序函数。注意优先队列的优先级设置方法和sort函数不太一样,刚好相反

struct cmp{
	bool operator()(const node &n1, const node &n2){
		if(n1.score!=n2.score)
			return n1.score<n2.score;
		else{
			if(n1.type!=n2.type)
				return n1.type>n2.type;
			else
				return n1.id>n2.id;
		}
	}
};

C++代码

细节很多,一定得耐心。

#include<iostream>
#include<queue>
#include<cstring>
using namespace std; 
struct node{
	int score; //分数 
	int type; //类别 
	int id;//编号 
}; 
struct cmp{
	bool operator()(const node &n1, const node &n2){
		if(n1.score!=n2.score)
			return n1.score<n2.score;
		else{
			if(n1.type!=n2.type)
				return n1.type>n2.type;
			else
				return n1.id>n2.id;
		}
	}
};
vector<node> invalid;//存放已经被删除的结点 
bool isValid(node n){
	int num = invalid.size();
	for(int i=0; i<num; i++){
		if(n.id==invalid[i].id&&n.type==invalid[i].type)
			return false;
	}
	return true;
} 
vector<int> q[55];//存放每一类选出的物品编号 
int limit[55];
int limit_num;
priority_queue<node, vector<node>, cmp> pq,temp;//存放商品信息
int m,n,num;//m类,每类初始n个商品, num次操作 
void query(){
	temp = pq;
//	temp1 = temp;
//	printf("------------------\n");
//	printf("当前优先队列中的值:\n"); 
//	while(!temp1.empty()){
//		node t = temp1.top();
//		printf("type:%d id:%d score:%d flag:%d\n",t.type, t.id, t.score,t.flag);
//		temp1.pop();
//	} 
//	printf("------------------\n");
	for(int i=0; i<m; i++){
		q[i].clear();
	}
	int k = limit_num;
	while(k>0&&temp.size()>0){//千万注意取队列首元素时要先判断是否非空 
		node top = temp.top();
		if(limit[top.type]>0&&isValid(top)){
			q[top.type].push_back(top.id);
			limit[top.type]--;
			k--;
		}
		temp.pop();
		//k--;
		//printf("In while\n");
	}
	//printf("out of while\n");
	for(int i=0; i<m; i++){
		int len = q[i].size();
		if(len>0){
			for(int j=0; j<len; j++){
				printf("%d",q[i][j]);
				if(j<q[i].size()-1){
					printf(" ");
				}
			}
			printf("\n");
		}
		else{
			printf("-1\n");
		}
	}
}
int main(){
	scanf("%d%d",&m,&n);
	node temp;
	for(int i=0; i<n; i++){
		scanf("%d%d",&temp.id, &temp.score);
		for(int j=0; j<m; j++){
			temp.type = j;
			pq.push(temp);
		}
	}
//	while(!pq.empty()){
//		node top = pq.top();
//		printf("type:%d id:%d score:%d\n",top.type, top.id, top.score);
//		pq.pop();
//	}
	scanf("%d",&num); 
	for(int i=0; i<num; i++){
		int opt,type,id;
		node tmp; 
		scanf("%d",&opt);
		switch(opt){
			case 1://增加
				int score;
				scanf("%d%d%d",&type, &id, &score);
				tmp.id = id;
				tmp.score = score;
				tmp.type = type;
				pq.push(tmp);
				break;
			case 2://删除 
				scanf("%d%d",&type, &id);
				node N;
				N.type = type;
				N.id = id;
				N.score = 0;
				invalid.push_back(N);
				break;
			case 3://查询 
				memset(limit,0,sizeof(limit));//清空limit数组 
				scanf("%d",&limit_num);
				for(int i=0; i<m; i++){
					scanf("%d",&limit[i]);
				}
				query(); 
				break;
		}
	}
	return 0;
} 

记录一下我的小开心~

发布了110 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40486952/article/details/103087967