CCF认证2014032-窗口

本人初学,水平有限,若有不足,恳请赐教!

1.方法1

根据题意,所有窗口的输入都是自底向上的,选中某个窗口此窗口会置为最顶端且其他窗口相对层叠次序不变。我们可以模拟这个过程。首先,在输入窗口坐标时令屏幕上此窗口范围内的所有点全部初始化为此窗口的编号,并且后输入的窗口可以覆盖之前的已有的窗口编号(画家算法),根据输入顺序恰好可以得到所有窗口的初始状态。然后,后续的点击操作如果选定的是某个窗口则输出此点的编号(即窗口的编号),并且对其进行“重染色”即根据窗口坐标重新对屏幕进行编号覆盖操作。如此反复即可得到正确结果。

显然,此方法存在大量的赋值操作,因此其时空复杂度均不高。

具体代码如下:

#include <iostream>
#include <vector>

using namespace std;

int mp[2600][1500];

typedef struct Point
{
	int x, y;
	Point(int x = 0, int y = 0) :x(x), y(y) {}
}Point;

int main()
{
	//FILE *stream;
	//freopen_s(&stream, "data.txt", "r", stdin);

	int n, m;
	cin >> n >> m;
	vector<pair<Point, Point>> vp(1); //存放窗口的两个坐标
	for(int i = 1; i <= n; i++)
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		vp.push_back({Point(x1, y1), Point(x2, y2)});
		//窗口覆盖
		for(int x = x1; x <= x2; x++)
		{
			for(int y = y1; y <= y2; y++)
			{
				mp[x][y] = i;
			}
		}
	}
	while(m--)
	{
		int curx, cury;
		cin >> curx >> cury;
		//对应位置为0说明此处没有任何窗口
		if(!mp[curx][cury]) cout << "IGNORED" << endl;
		else
		{
			int t = mp[curx][cury];
			cout << t << endl;
			auto p1 = vp[t].first;
			auto p2 = vp[t].second;
			//重染色
			for(int x = p1.x; x <= p2.x; x++)
			{
				for(int y = p1.y; y <= p2.y; y++)
				{
					mp[x][y] = t;
				}
			}
		}
	}

	//fclose(stream);

	return 0;
}

2.方法2

考虑使用一个链表来依次存放各窗口的信息,链表由头到尾依次代表各窗口的从上到下的次序。对于每一次点击操作,都对链表由头到尾进行遍历,一旦发现符合条件的窗口则将其置于链表头部并输出窗口编号。

具体代码如下:

#include <iostream>
#include <list>

using namespace std;

typedef struct Windows
{
	int id; //窗口编号
	int x1, y1;
	int x2, y2;
	Windows(int id, int x1, int y1, int x2, int y2) :
		id(id), x1(x1), y1(y1), x2(x2), y2(y2)
	{}
}Windows;

int main()
{
	//FILE *stream;
	//freopen_s(&stream, "data.txt", "r", stdin);

	int n, m;
	cin >> n >> m;
	list<Windows> lw;
	for(int i = 1; i <= n; i++)
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		//头插法插入各结点,从头到尾为从窗口由上到下的次序
		lw.push_front(Windows(i, x1, y1, x2, y2));
	}
	while(m--)
	{
		int x, y;
		cin >> x >> y;
		auto iter = lw.begin();
		//注意不要在循环结构内修改链表结构,不然会出错
		for(; iter != lw.end(); iter++)
		{
			int x1, y1, x2, y2;
			x1 = iter->x1, y1 = iter->y1, x2 = iter->x2, y2 = iter->y2;
			if(x1 <= x && x <= x2 && y1 <= y && y <= y2)
			{
				break; //一旦发现符合条件的窗口则跳出循环
			}
		}
		//没有找到符合要求的窗口则输出"IGNORED"
		if(iter == lw.end()) cout << "IGNORED" << endl;
		//否则输出窗口编号并调整链表
		else
		{
			cout << iter->id << endl;
			Windows t = *iter;
			lw.push_front(t);
			lw.erase(iter);
		}
	}

	//fclose(stream);

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值