原题:https://pintia.cn/problem-sets/994805342720868352/problems/994805419468242944
题目大意
np为老鼠的体重,ng为每组最多的老鼠数量,给出每个老鼠的体重,和初始顺序。然后每ng个老鼠为一组,挑选每组中体重最大的老鼠晋级下一轮,然后剩下的未晋级的老鼠给予相同评级,即若当前晋级group
只老鼠,则剩下老鼠的评级统一为group+1
,直到所有老鼠评级完成,进行输出。
初步想法
由于需要一个数据结构,来存储老鼠,且每次需要从中挑选出晋级的老鼠晋级,之后依次循环进行比较。这里,我使用队列queue
来存储初始老鼠,然后每ng
个老鼠中挑选最重的老鼠进行晋级,晋级的结果是 将该老鼠编号压入队列尾部 方便下一次比较,每次用一个数组book
来记录已晋级的老鼠,最后一轮之后,给没有晋级的老鼠进行评级,级别为晋级老鼠个数(队列长度)+1
,直到队列元素只有一只老鼠时,它就是第一名,此时比赛停止。
/* 1056 Mice and Rice (25 分) */
// 队列来模拟排序晋级
#include<queue>
#include<vector>
#include<iostream>
using namespace std;
int main() {
int DEBUG = 0;
int np, ng;
vector<int> weight;
vector<int> rank;
vector<int> book;
queue<int> Q; // 模拟排序
scanf("%d %d", &np, &ng);
weight.resize(np); rank.resize(np); book.resize(np);
int i, index;
for (i = 0; i < np; i++) scanf("%d", &weight[i]);
for (i = 0; i < np; i++) {
scanf("%d", &index);
Q.push(index);
}
// 开始模拟排序晋级
int len = Q.size(); // 表示上一轮队列的长度
while (len != 1) {
for (i = 0; i < len;) {
int maxindex = i, maxweight = -1;
int j;
for (j = i; j < i + ng && j < len; j++) {
index = Q.front(); Q.pop();
if (DEBUG) printf("当前参与排名的老鼠%d\n", index);
if (weight[index] > maxweight) {
maxweight = weight[index];
maxindex = index;
}
}
if (DEBUG) printf("晋级选手%d\n", maxindex);
book[maxindex] = 1; // 晋级
Q.push(maxindex); // 进队参与下一次比较
i = j;
}
len = Q.size(); // 下一次比较的老鼠数,也是这一轮晋级的老鼠个数
if (DEBUG) printf("本轮竞晋级完毕,排名为%d\n", len + 1);
for (i = 0; i < np; i++) {
if (book[i] == 0 && rank[i] == 0) // 没晋级也没排名
rank[i] = len + 1;
}
fill(book.begin(), book.end(), 0);
}
rank[Q.front()] = 1; // 排序第一名
for (i = 0; i < np; i++) {
printf("%d", rank[i]);
i != np - 1 ? printf(" ") : printf("\n");
}
system("pause");
return 0;
}
上图是晋级示意图。
小优化
每次我们使用了数组book
来记录晋级的老鼠,然后对其他老鼠进行评级,但是这样我们在每一轮排序前都要重置该数组,而且搜索未晋级和未评级的老鼠时要对数组进行全局搜索,因此我们可以使用其他方法来避免对该数组的使用。
即我们在每次对老鼠进行评级前,先计算出本轮未晋级老鼠的评级是多少,即假如队列中有n
只老鼠,若n
可被ng
整除,则我们可以分为group = n / ng
组;若n
不可被ng
整除,则我们可以分成group = n/ng + 1
组。此时,本次的评级为group+1
,我们对该队列中的所有老鼠进行评级,同时,晋级的老鼠重新压入队列,这样,这些老鼠在之后会被重新进行评级,则我们不需要每次记录晋级老鼠了。
/* 1056 Mice and Rice (25 分) */
// 队列来模拟排序晋级
#include<queue>
#include<vector>
#include<iostream>
using namespace std;
int main() {
int np, ng;
vector<int> weight;
vector<int> rank;
queue<int> Q; // 模拟排序
scanf("%d %d", &np, &ng);
weight.resize(np); rank.resize(np);
int i, index;
for (i = 0; i < np; i++) scanf("%d", &weight[i]);
for (i = 0; i < np; i++) {
scanf("%d", &index);
Q.push(index);
}
// 开始模拟排序晋级
int len = Q.size(); // 表示上一轮队列的长度
while (len != 1) {
int group = len / ng;
if (len % ng != 0) group++;//本次晋级的老鼠
for (i = 0; i < len;) {
int maxindex = i, maxweight = -1;
int j;
for (j = i; j < i + ng && j < len; j++) {
index = Q.front(); Q.pop();
rank[index] = group + 1; // 对本轮的所有老鼠进行评级
if (weight[index] > maxweight) {
maxweight = weight[index];
maxindex = index;
}
}
Q.push(maxindex); // 进队参与下一次比较
i = j;
}
len = group;
}
rank[Q.front()] = 1; // 排序第一名
for (i = 0; i < np; i++) {
printf("%d", rank[i]);
i != np - 1 ? printf(" ") : printf("\n");
}
system("pause");
return 0;
}