CSP-CCF 201403-2 窗口

目录

一、问题描述

二、解答

方法1:链表

方法2:使用结构体和数组

三、总结


一、问题描述

问题描述

  在某图形操作系统中,有 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创建进来,可能会更加方便

关于链表的使用可以参考博客:实用库/函数之链表的使用-CSDN博客

代码:

#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;

}

三、总结

当看到这一题的时候,首先想到的是数组,但是又觉得数组交换起来很麻烦,然后重新复习了一下链表,使用链表来做。但是后来发现使用数组其实也没那么麻烦。

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值