1. 窗口问题
【问题描述】
在某图形操作系统中,有N个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域。窗口的边界上的点也属于该窗口。窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的内容。
当你点击屏幕上一个点的时候,你就选择了处于被点击位置的最顶层窗口,并且这个窗口就会被移到所有窗口的最顶层,而剩余的窗口的层次顺序不变。如果你点击的位置不属于任何窗口,则系统会忽略你这次点击。
现在我们希望你写一个程序模拟点击窗口的过程。
【输入形式】
输入的第一行有两个正整数,即N和M。(1≤N≤10,1≤M≤10)接下来N行按照从最下层到最顶层的顺序给出N个窗口的位置。每行包含四个非负整数x1,y1,x2,y2,表示该窗口的一对顶点坐标分别为(x1,y1)和(x2,y2)。保证x1<x2,y1<y2。
接下来M行每行包含两个非负整数x,y,表示一次鼠标点击的坐标。题目中涉及到的所有点和矩形的顶点的x,y坐标分别不超过2559和1439。
【输出形式】
输出包括M行,每一行表示一次鼠标点击的结果。如果该次鼠标点击选择了一个窗口,则输出这个窗口的编号(窗口按照输入中的顺序从1编号到N);如果没有,则输出"IGNORED"(不含双引号)。
【样例输入】
3 4
0 0 4 4
1 1 5 5
2 2 6 6
1 1
0 0
4 4
0 5
【样例输出】
2
1
1
IGNORED
【样例说明】
第一次点击的位置同时属于第1和第2个窗口,但是由于第2个窗口在上面,它被选择并且被置于顶层。
第二次点击的位置只属于第1个窗口,因此该次点击选择了此窗口并将其置于顶层。现在的三个窗口的层次关系与初始状态恰好相反了。第三次点击的位置同时属于三个窗口的范围,但是由于现在第1个窗口处于顶层,它被选择。
最后点击的(0,5)不属于任何窗口。
【评分标准】
参考代码:
#include<iostream>
using namespace std;
#define SIZE 100
typedef struct ElemType{
int x1, y1, x2, y2;
int index;
}ElemType;
typedef struct SqList {
ElemType* elem;
int len;
int lsize;
}SqList;
void InitList(SqList& L) {
L.elem = (ElemType*)malloc(SIZE * sizeof(ElemType)+1);
if (!L.elem)exit(-2);
L.len = 0;
L.lsize = SIZE;
}
void InsertList(SqList& L, int N) {
for (int i = 1; i <= N; i++) {//0号位置不用
L.elem[i].index = i;//记录窗口标号
cin >> L.elem[i].x1 >> L.elem[i].y1 >> L.elem[i].x2 >> L.elem[i].y2;
L.len++;
}
}
#define MAXSIZE 100
#define RESIZE 10
typedef ElemType SElemType;
typedef struct {
SElemType* base;
SElemType* top;
int size;
}Stack;
void InitStack(Stack& s) {
s.base = (SElemType*)malloc(MAXSIZE * sizeof(SElemType));
if (!s.base)
exit(-2);
s.top = s.base;
s.size = MAXSIZE;
}
bool IsEmpty(Stack S) {
if (S.base == S.top)
return true;
return false;
}
void Push(Stack& s, SElemType e) {
if (s.top - s.base >= s.size) {
s.base = (SElemType*)realloc(s.base, (MAXSIZE + RESIZE) * sizeof(SElemType));
if (!s.base)
exit(-2);
s.top = s.base + s.size;
s.size += MAXSIZE;
}
*s.top++ = e;
}
void Pop(Stack& s, SElemType& e) {
if (s.top == s.base)
return;
e = *--s.top;
}
SElemType gettop(Stack s) {
if (s.top != s.base)
return *(s.top - 1);
}
//将线性表的数据放到栈
void LtoS(Stack& S, SqList L) {
for (int i = 1; i <= L.len; i++)
Push(S, L.elem[i]);
}
//将栈S1的某个元素移到S2
void S1toS2(Stack& S1,Stack& S2,SElemType& e) {
Pop(S1, e);
Push(S2, e);
}
//将栈S2的某个元素移到S1
void S2toS1(Stack& S1, Stack& S2, SElemType& e) {
Pop(S2, e);
Push(S1, e);
}
//判断
void Judge(int M, Stack& S1, Stack S2,int N) {//S1用于存放初始窗口以及点击之后的窗口,S2用于存放不符合要求的窗口
SElemType e;
int x, y, flag ;
for (int i = 0; i < M; i++) {
flag = 0;
cin >> x >> y;
for (int i = 0; i < N; i++) {
if (x<gettop(S1).x1 || y<gettop(S1).y1 || x>gettop(S1).x2 || y>gettop(S1).y2) {
S1toS2(S1, S2, e);//不在窗口内,将该窗口从S1移动到S2
}
else {
flag = 1;
Pop(S1, e);
SElemType top = e;
cout << e.index << endl;
//找到之后应该调整窗口顺序,将选择的窗口移到顶层
while (!IsEmpty(S2))
S2toS1(S1, S2, e);
Push(S1, top);
break;
}
}
if (flag == 0) {
while (!IsEmpty(S2))
S2toS1(S1, S2, e);//未选择任何一个窗口,将S2中所有窗口原路返还给S1
cout << "IGNORED" << endl;
}
}
}
int main() {
int N, M;
cin >> N >> M;
SqList L;
InitList(L);
InsertList(L, N);
Stack S1, S2;
InitStack(S1);
InitStack(S2);
LtoS(S1, L);
Judge(M, S1, S2,N);
}
2. 学生排队
【问题描述】
体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。
例如,下面给出了一组移动的例子,例子中学生的人数为8人。
0)初始队列中学生的学号依次为1, 2, 3, 4, 5, 6, 7, 8;
1)第一次调整,命令为“3号同学向后移动2”,表示3号同学出队,向后移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 3, 6, 7, 8;
2)第二次调整,命令为“8号同学向前移动3”,表示8号同学出队,向前移动3名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 8, 3, 6, 7;
3)第三次调整,命令为“3号同学向前移动2”,表示3号同学出队,向前移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 3, 5, 8, 6, 7。
小明记录了所有调整的过程,请问,最终从前向后所有学生的学号依次是多少?
请特别注意,上述移动过程中所涉及的号码指的是学号,而不是在队伍中的位置。在向后移动时,移动的距离不超过对应同学后面的人数,如果向后移动的距离正好等于对应同学后面的人数则该同学会移动到队列的最后面。在向前移动时,移动的距离不超过对应同学前面的人数,如果向前移动的距离正好等于对应同学前面的人数则该同学会移动到队列的最前面。
【输入形式】
输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。
第二行包含一个整数m,表示调整的次数。
接下来m行,每行两个整数p, q,如果q为正,表示学号为p的同学向后移动q,如果q为负,表示学号为p的同学向前移动-q。
【输出形式】
输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,表示最终从前向后所有学生的学号。
【样例输入】
8
3
3 2
8 -3
3 -2
【样例输出】
1 2 4 3 5 8 6 7
【样例说明】
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。
【评分标准】
参考代码:
#include<iostream>
using namespace std;
#define SIZE 100
typedef int ElemType;
typedef struct SqList {
ElemType* elem;
int len;
int lsize;
}SqList;
void InitList(SqList& L) {
L.elem = (ElemType*)malloc(SIZE * sizeof(ElemType) + 1);
if (!L.elem)exit(-2);
L.len = 0;
L.lsize = SIZE;
}
void InsertList(SqList& L, int n) {
for (int i = 0; i < n; i++) {
L.elem[i] = i+1;
L.len++;
}
}
void Swap(int& a, int& b) {
int t = a; a = b; b = t;
}
void Select(SqList& L, int n, int m) {
int p, q;
for (int i = 0; i < m; i++) {
cin >> p >> q;
for (int j = 0; j < n; j++) {
if (L.elem[j] == p) {
if (q > 0) {
for (int k = j; k < j + q; k++)//后移
Swap(L.elem[k], L.elem[k + 1]);
break;
}
else {
for (int k = j; k > j + q; k--)
Swap(L.elem[k], L.elem[k - 1]);//前移
break;
}
}
}
}
}
int main() {
int n, m;
cin >> n >> m;
SqList L;
InitList(L);
InsertList(L, n);
Select(L, n, m);
for (int i = 0; i < n;i++)
cout << L.elem[i] << " ";
}
3. 地铁修建
【问题描述】
A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号到n号枢纽间修建一条地铁。
地铁由很多段隧道组成,每段隧道连接两个交通枢纽。经过勘探,有m段隧道作为候选,两个交通枢纽之间最多只有一条候选的隧道,没有隧道两端连接着同一个交通枢纽。
现在有n家隧道施工的公司,每段候选的隧道只能由一个公司施工,每家公司施工需要的天数一致。而每家公司最多只能修建一条候选隧道。所有公司同时开始施工。
作为项目负责人,你获得了候选隧道的信息,现在你可以按自己的想法选择一部分隧道进行施工,请问修建整条地铁最少需要多少天。
【输入形式】
输入的第一行包含两个整数n, m,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量。
第2行到第m+1行,每行包含三个整数a, b, c,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天。
【输出形式】
输出一个整数,修建整条地铁线路最少需要的天数。【样例输入】
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
【样例输出】
6
【样例说明】
可以修建的线路有两种。
第一种经过的枢纽依次为1, 2, 3, 6,所需要的时间分别是4, 4, 7,则整条地铁线需要7天修完;
第二种经过的枢纽依次为1, 4, 5, 6,所需要的时间分别是2, 5, 6,则整条地铁线需要6天修完。
第二种方案所用的天数更少。
【评测用例规模与约定】
2 ≤ n ≤ m ≤ 100,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000。
所有评测用例保证在所有候选隧道都修通时1号枢纽可以通过隧道到达其他所有枢纽。
【评分标准】
参考代码:
#include<iostream>
using namespace std;
#define INFINITY 2147483647
#define MAX_VERTEX_NUM 20 //最大顶点数
typedef int VRType;
typedef struct ArcCell {
VRType adj;//顶点关系类型(天数)
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
AdjMatrix arcs;//邻接矩阵
int vexnum;//图的当前顶点数
VRType vexs[MAX_VERTEX_NUM];//存储顶点
}MGraph;
//查找顶点下标
int LocateVex(MGraph G, int v) {
int i = 0;
for (; i < G.vexnum; i++) {
if (G.vexs[i] == v) {
break;
}
}
//如果找不到返回-1
if (i > G.vexnum)
return -1;
return i;
}
//返回较大值
int Max(int a, int b) {
return a > b ? a : b;
}
//创建图
void CreatGraph(MGraph& G, int n, int m) {
G.vexnum = n;
for (int i = 0; i < G.vexnum; i++)
G.vexs[i] = i + 1;
for (int i = 0; i < G.vexnum; i++)
for (int j = 0; j < G.vexnum; j++)
G.arcs[i][j].adj = INFINITY;
int a, b, c;//a b为顶点(交通枢纽),c为权重
for (int i = 0; i < m; i++) {
cin >> a >> b >> c;
int x = LocateVex(G, a);
int y = LocateVex(G, b);
G.arcs[x][y].adj = c;
G.arcs[y][x].adj = c;//无向图
}
}
//迪杰斯特拉算法,v0表示源点下标
void DIJ(MGraph G, int v0, int pre[MAX_VERTEX_NUM], int dist[MAX_VERTEX_NUM]) {
bool flag[MAX_VERTEX_NUM];//确认该顶点是否已经找到最短路径
for (int i = 0; i < G.vexnum; i++) {
flag[i] = false;
dist[i] = G.arcs[v0][i].adj;
pre[i] = 0;
}
//由于以v0位下标的顶点为起始点,所以不用再判断
dist[v0] = 0;
flag[v0] = true;
int k = 0;
for (int i = 0; i < G.vexnum; i++) {
int min = INFINITY;
//选择到各顶点权值最小的顶点,即为本次能确定最短路径的顶点
for (int j = 0; j < G.vexnum; j++) {
if (!flag[j]) {
if (dist[j] < min) {
k = j;
min = dist[j];
}
}
}
//该顶点的标志位为true,避免重复判断
flag[k] = true;
//对v0到各顶点的权值进行修正
for (int i = 0; i < G.vexnum; i++) {
if (!flag[i] && (Max(min, G.arcs[k][i].adj) < dist[i])) {//如果最短路径的最大权重大于当前权重,则修正
dist[i] = Max(min, G.arcs[k][i].adj);
pre[i] = k;//记录各个最短路径上存在的顶点
}
}
}
}
int main() {
MGraph G;
int n, m;
cin >> n >> m;
int pre[MAX_VERTEX_NUM], dist[MAX_VERTEX_NUM];
CreatGraph(G,n,m);
DIJ(G, 0, pre, dist);
cout << dist[G.vexnum - 1];
}