目录
一、问题描述
问题描述
在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域。窗口的边界上的点也属于该窗口。窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的内容。
当你点击屏幕上一个点的时候,你就选择了处于被点击位置的最顶层窗口,并且这个窗口就会被移到所有窗口的最顶层,而剩余的窗口的层次顺序不变。如果你点击的位置不属于任何窗口,则系统会忽略你这次点击。
现在我们希望你写一个程序模拟点击窗口的过程。
输入格式
输入的第一行有两个正整数,即 N 和 M。(1 ≤ N ≤ 10,1 ≤ M ≤ 10)
接下来 N 行按照从最下层到最顶层的顺序给出 N 个窗口的位置。 每行包含四个非负整数 x1, y1, x2, y2,表示该窗口的一对顶点坐标分别为 (x1, y1) 和 (x2, y2)。保证 x1 < x2,y1 2。
接下来 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) 不属于任何窗口。
二、解答
方法1:链表
使用头插法来创建链表,这样的话,在后输入的顶层的窗口就被移到前面了。然后在被选择并将该窗口置于最顶层,只需巧妙利用指针即可。
注意:①此方法的编译环境必须选择使用cpp11或者cpp14,否则会出现编译错误的问题;
②遍历链表不宜使用for循环,应该使用while循环:while(L!=nullptr)
③这里创建结点也可以把x1,y1,x2,y2创建进来,可能会更加方便
关于链表的使用可以参考博客:实用库/函数之链表的使用-优快云博客
代码:
#include<iostream>
using namespace std;
struct node {
int num;
struct node* next;
};
bool inWindow(int a1, int b1, int a2, int b2, int a, int b)
{
if (a >= a1 && a <= a2 && b >= b1 && b <= b2)
{
return true;
}
else {
return false;
}
}
int main()
{
int N, M;
cin >> N >> M;
int x1[11] = { 0 };
int y1[11] = { 0 };
int x2[11] = { 0 };
int y2[11] = { 0 };
node* head = new node;
head->next = nullptr;
for (int i = 1; i <= N; i++)
{
node* s = new node;
//cin >> s->x1 >> s->y1 >> s->x2 >> s->y2;
cin >> x1[i] >> y1[i] >> x2[i] >> y2[i];
s->num = i;
s->next = head->next;
head->next = s;
}
int x[10] = { 0 };
int y[10] = { 0 };
for (int i = 0; i < M; i++)
{
cin >> x[i] >> y[i];
}
for (int i = 0; i < M; i++)
{
node* L = head ->next;
node* pre = head;
int count = 0;
//for (int j = 1; j <=N; j++)
while(L!=nullptr)
//注意:这里不能用for循环!!!遍历链表最好使用while循环
{
//if (inWindow(x1[j], y1[j], x2[j], y2[j], x[i], y[i]) == false)
if (!inWindow(x1[L->num], y1[L->num], x2[L->num], y2[L->num], x[i], y[i]))
{
pre = L;
L = pre->next;
count++;
}
else {
cout << L->num << endl;
// 移除L节点
pre->next = L->next;
// 将L节点插入到链表头部
L->next = head->next;
head->next = L;
break;
}
}
if(count==N)
{
cout << "IGNORED" << endl;
}
}
return 0;
}
方法2:使用结构体和数组
注:①这里可以用C++编译;②再次警告:不能一边输入一边输出!!!
tips:
关于当前元素移动到最后面,其他元素依次向前移动的代码:
Window temp = window[j];
while (j < N - 1)//分析:因为到window[N-2]=windwow[N-1]时结束交换
{
window[j] = window[j + 1];
j++;
}
window[N - 1] = temp;
全部代码为:
#include<iostream>
using namespace std;
//创建window结构体
struct Window {
int x1;
int y1;
int x2;
int y2;
int num;//记录编号
};
bool inWindow(int a1, int b1, int a2, int b2, int a, int b)
{
if (a >= a1 && a <= a2 && b >= b1 && b <= b2)
{
return true;
}
else {
return false;
}
}
int main()
{
int N, M;
cin >> N >> M;
Window window[10];//下标也是从0开始
for (int i = 0; i < N; i++)
{
cin >> window[i].x1 >> window[i].y1 >> window[i].x2 >> window[i].y2;
window[i].num = i + 1;
}
int x[10] = { 0 };
int y[10] = { 0 };
for (int i = 0; i < M; i++)
{
cin >> x[i] >> y[i];
}
for (int i = 0; i < M; i++)
{
//cin >> x[i] >> y[i];
//再次警告:不能一边输入一边输出!!!
int count = 0;
for (int j = N-1; j >=0;j--)
{
if (inWindow(window[j].x1, window[j].y1, window[j].x2, window[j].y2, x[i], y[i]) == true)
{
cout << window[j].num << endl;
//开始交换顺序
Window temp = window[j];
while (j < N - 1)//分析:因为到window[N-2]=windwow[N-1]时结束交换
{
window[j] = window[j + 1];
j++;
}
window[N - 1] = temp;
break;//退出当前for循环
}
else {
count++;
}
}
if (count == N)
{
cout << "IGNORED" << endl;
}
}
return 0;
}
三、总结
当看到这一题的时候,首先想到的是数组,但是又觉得数组交换起来很麻烦,然后重新复习了一下链表,使用链表来做。但是后来发现使用数组其实也没那么麻烦。