试题编号: | 201703-2 |
试题名称: | 学生排队 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。 输入格式 输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。 输出格式 输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,表示最终从前向后所有学生的学号。 样例输入 8 样例输出 1 2 4 3 5 8 6 7 评测用例规模与约定 对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。 |
问题链接:CCF201703试题
问题描述:(参见上文)
问题分析:
这是一个模拟题,关键在于数据表示。
程序说明:
方法一:
数组sno2pos[]用于存储各个学生(学号)所在的位置;数组pos2sno[]是索引,pos2sno[i]=s表示学生s位于位置i。这个程序应该是最快速的版本。
方法二:
数组pos2sno[]用于存储各个所在的位置上的学生(学号),pos2sno[i]=s表示学生s位于位置i。这个方法是直接进行模拟。其缺点是每次需要找到指定学生(学号)的位置,顺序查找需要花费时间;优点是逻辑相对简单并且易于理解。
方法三:
使用链表来实现,是一种最容易想到的方法。这个程序的关键是如何使用STL的list(链表)实现模拟。
程序中的28-33行,有关迭代器指针移动的逻辑是不是可以改进?
方法四:
使用STL的向量vector来实现。实际上是一种代码最为简洁的做法。
需要注意的是下标运算逻辑。
以上几种做法中,从得分考虑则推荐方法二,从时空考虑推荐方法一。其他则是使用STL实现的方法,也值得考虑。
提交后得100分的C++语言程序(方法四)如下:
/* CCF201703-2 学生排队 */
#include <iostream>
#include <vector>
using namespace std;
vector<int> v;
int find(int x)
{
int ret = - 1;
for(int i = 0; i < (int)v.size(); i++)
if(v[i] == x)
return i;
return ret;
}
int main()
{
int n, m, p, q;
// 读入数据
cin >> n >> m;
// 初始化
for(int i=1; i<=n; i++)
v.push_back(i);
// 模拟移动过程
for(int i=1; i<=m; i++) {
cin >> p >> q;
int pos = find(p);
v.insert(v.begin() + pos + (q > 0 ? q + 1 : q), p);
v.erase(v.begin() + pos + (q < 0 ? 1 : 0));
}
// 输出结果
cout << v[0];
for(int i = 1; i < (int)v.size(); i++)
cout << " " << v[i];
cout << endl;
return 0;
}
提交后得100分的C++语言程序(方法三)如下:
/* CCF201703-2 学生排队 */
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;
int main()
{
int n, m, p, q;
list<int> l;
// 读入数据
cin >> n >> m;
// 初始化
for(int i=1; i<=n; i++)
l.push_back(i);
// 模拟移动过程
for(int i=1; i<=m; i++) {
cin >> p >> q;
list<int>::iterator iter = find(l.begin(), l.end(), p);
list<int>::iterator iter2 = iter;
if(q > 0)
for(int i=0; i<=q; i++)
iter2++;
else
for(int i=1; i<=-q; i++)
iter2--;
l.insert(iter2, p);
l.erase(iter);
}
// 输出结果
list<int>::iterator iter = l.begin();
cout << *iter;
for(iter++; iter != l.end(); iter++)
cout << " " << *iter;
cout << endl;
return 0;
}
提交后得100分的C语言程序(方法二)如下:
/* CCF201703-2 学生排队 */
#include <stdio.h>
#define N 1000
int pos2sno[N+1]; // 位置上的学号
int find(int sno)
{
int i;
for(i = 1; pos2sno[i] != sno; i++)
;
return i;
}
int main(void)
{
int n, m, p, q, i, j;
// 读入数据
scanf("%d%d", &n, &m);
// 初始化
for(i=1; i<=n; i++)
pos2sno[i] = i;
// 模拟移动过程
for(i=1; i<=m; i++) {
scanf("%d%d", &p, &q);
int pos = find(p);
if(q > 0) {
for(j=pos; j<pos+q; j++)
pos2sno[j] = pos2sno[j + 1];
pos2sno[pos + q] = p;
} else {
for(j=pos; j>pos+q; j--)
pos2sno[j] = pos2sno[j - 1];
pos2sno[pos + q] = p;
}
}
// 输出结果
printf("%d", pos2sno[1]);
for(i=2; i<=n; i++)
printf(" %d", pos2sno[i]);
printf("\n");
return 0;
}
提交后得100分的C++语言程序(方法一)如下(简洁版):
/* CCF201703-2 学生排队 */
#include <iostream>
using namespace std;
const int N = 1000;
int sno2pos[N+1]; // 学号所在位置
int pos2sno[N+1]; // 位置上的学号
int main()
{
int n, m, p, q;
// 读入数据
cin >> n >> m;
// 初始化
for(int i=1; i<=n; i++) {
sno2pos[i] = i;
pos2sno[i] = i;
}
// 模拟移动过程
for(int i=1; i<=m; i++) {
int pos1, pos2, sno2;
cin >> p >> q;
if(q != 0) {
int move = (q > 0) ? 1 : -1;
int end = (q > 0) ? q : -q;
pos1 = sno2pos[p];
for(int i=1; i<=end; i++) {
sno2 = pos2sno[pos1 + move];
pos2 = sno2pos[sno2];
pos2sno[pos1] = sno2;
sno2pos[sno2] = pos1;
pos1 = pos2;
}
pos2sno[pos2] = p;
sno2pos[p] += q;
}
}
// 输出结果
cout << pos2sno[1];
for(int i=2; i<=n; i++)
cout << " " << pos2sno[i];
cout << endl;
return 0;
}
提交后得100分的C++语言程序如下:
#include <iostream>
using namespace std;
//#define DEBUG
const int N = 1000;
int sno2pos[N+1]; // 学号所在位置
int pos2sno[N+1]; // 位置上的学号
int main()
{
int n, m, p, q;
cin >> n >> m;
for(int i=1; i<=n; i++) {
sno2pos[i] = i;
pos2sno[i] = i;
}
for(int i=1; i<=m; i++) {
int pos1, pos2, sno2;
cin >> p >> q;
if(q != 0) {
int move, end;
if(q > 0) {
move = 1;
end = q;
} else {
move = -1;
end = -q;
}
pos1 = sno2pos[p];
for(int i=1; i<=end; i++) {
sno2 = pos2sno[pos1 + move];
pos2 = sno2pos[sno2];
pos2sno[pos1] = sno2;
sno2pos[sno2] = pos1;
pos1 = pos2;
}
pos2sno[pos2] = p;
sno2pos[p] += q;
}
// if(q > 0) {
// pos1 = sno2pos[p];
// for(int i=1; i<=q; i++) {
// sno2 = pos2sno[pos1+1];
// pos2 = sno2pos[sno2];
// pos2sno[pos1] = sno2;
// sno2pos[sno2] = pos1;
// pos1 = pos2;
// }
// pos2sno[pos2] = p;
// sno2pos[p] += q;
// } else if(q < 0){
// pos1 = sno2pos[p];
// for(int i=1; i<=-q; i++) {
// sno2 = pos2sno[pos1-1];
// pos2 = sno2pos[sno2];
// pos2sno[pos1] = sno2;
// sno2pos[sno2] = pos1;
// pos1 = pos2;
// }
// pos2sno[pos2] = p;
// sno2pos[p] += q;
// }
#ifdef DEBUG
cout << "son: ";
for(int i=1; i<=n; i++)
cout << pos2sno[i] << " ";
cout << endl;
cout << "pos: ";
for(int i=1; i<=n; i++)
cout << sno2pos[i] << " ";
cout << endl;
#endif
}
cout << pos2sno[1];
for(int i=2; i<=n; i++)
cout << " " << pos2sno[i];
cout << endl;
return 0;
}