原题链接
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;
}
记录一下我的小开心~