题目描述
题目要求模拟一个窗口管理器。屏幕大小为 1024×10241024 \times 10241024×1024,原点在左上角。窗口有四个区域:关闭框(左上角 25×2525 \times 2525×25)、缩放框(右上角 25×2525 \times 2525×25)、移动栏(顶部 252525 像素,除去关闭和缩放框)、数据区(剩余区域)。支持的事件:
CR l t r b:创建新窗口(ID\texttt{ID}ID 递增),置于最前。RE:重绘所有窗口(从后到前输出)。DN x y:按下鼠标,选中可见区域的窗口并置前。UP x y:释放鼠标,根据按下和释放的位置及区域执行相应操作(关闭、缩放、移动)。AT x y:鼠标移动,若在移动窗口中则输出新位置。ZZ:结束。
输入格式
输入包含多行,每行一个事件。输入以 ZZ 结束。
输出格式
根据事件输出相应消息,格式见样例。
样例
输入
CR 0 0 200 200
CR 50 50 250 250
RE
DN 195 5
AT 50 50
UP 198 6
AT 100 100
AT 1000 1000
DN 1020 10
UP 1020 10
RE
DN 100 100
UP 800 0
DN 0 700
UP 1023 1023
DN 50 10
AT 70 70
UP 100 100
DN 60 60
RE
ZZ
输出
Created window 0 at 0, 0, 200, 200
Created window 1 at 50, 50, 250, 250
Window 0 at 0, 0, 200, 200
Window 1 at 50, 50, 250, 250
Selected window 0
Resized window 0 to 0, 0, 1023, 1023
Selected window 0
Resized window 0 to 0, 0, 200, 200
Window 1 at 50, 50, 250, 250
Window 0 at 0, 0, 200, 200
Selected window 0
Selected window 0
Moved window 0 to 20, 60, 220, 260
Moved window 0 to 50, 90, 250, 290
Selected window 1
Closed window 1
Window 0 at 50, 90, 250, 290
题目分析
本题的核心是维护窗口的层次顺序和状态,并处理鼠标事件。
数据结构
- 使用映射存储窗口信息:ID\texttt{ID}ID、位置、是否全屏。
- 使用向量
zOrder存储窗口的层次顺序(索引越小越靠后)。
事件处理
CR:创建窗口,加入zOrder末尾(最前),输出创建信息。RE:按zOrder顺序输出窗口位置(全屏时输出0,0,1023,1023)。DN:找到鼠标位置所在的窗口(从后到前检查),若找到则将其移到zOrder末尾(置前),输出选中信息。记录按下时的位置和区域。AT:若正在移动窗口(isWindowMoving),则移动窗口并输出新位置。UP:根据按下和释放的位置判断操作:- 若在移动栏且窗口非全屏,则移动窗口。
- 若在相同窗口的相同区域:
- 关闭框:删除窗口。
- 缩放框:切换全屏状态,输出新位置。
注意事项
- 全屏窗口不能移动。
- 移动窗口时,若鼠标移动则立即更新位置并输出。
复杂度分析
每个事件 O(窗口数)O(\text{窗口数})O(窗口数),窗口数有限。
代码实现
// WIMP
// UVa ID: 577
// Verdict: Accepted
// Submission Date: 2017-05-17
// UVa Run Time: 0.000s
//
// 版权所有(C)2017,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
const int CLOSE_BOX = 0, ZOOM_BOX = 1, MOTION_BAR = 2, DATA_AREA = 3, EMPTY = -1;
struct window {
int id;
int left, top, right, bottom;
int fullscreen;
bool contains(int area, int x, int y) {
int l = left, t = top, r = right, b = bottom;
if (fullscreen) l = 0, t = 0, r = 1023, b = 1023;
if (area == CLOSE_BOX) return x >= l && x <= (l + 24) && y >= t && y <= (t + 24);
if (area == ZOOM_BOX) return x >= (r - 24) && x <= r && y >= t && y <= (t + 24);
if (area == MOTION_BAR) return x >= (l + 25) && x <= (r - 25) && y >= t && y <= (t + 24);
if (area == DATA_AREA) return x >= l && x <= r && y >= (t + 25) && y <= b;
}
};
int windowId = 0;
int mouseX, mouseY, lastMouseX, lastMouseY;
int mouseDownArea, mouseDownWindowId;
int isMouseDown = 0, isWindowMoving = 0;
map<int, window > windows;
vector<int> zOrder;
void findMouse(int x, int y, int &mouseId, int &mouseArea, int &idx) {
mouseId = EMPTY, mouseArea = EMPTY, idx = -1;
for (int i = 0; i < zOrder.size(); i++)
for (int area = CLOSE_BOX; area <= DATA_AREA; area++)
if (windows[zOrder[i]].contains(area, x, y))
mouseId = zOrder[i], idx = i, mouseArea = area;
}
void displayWindow(int id) {
cout << windows[id].left << ", " << windows[id].top << ", ";
cout << windows[id].right << ", " << windows[id].bottom << "\n";
}
void moveWindow(int id, int offsetX, int offsetY) {
windows[id].left += offsetX;
windows[id].top += offsetY;
windows[id].right += offsetX;
windows[id].bottom += offsetY;
cout << "Moved window " << id << " to ";
displayWindow(id);
}
void createWindow() {
int left, top, right, bottom;
cin >> left >> top >> right >> bottom;
windows[windowId] = window{windowId, left, top, right, bottom, 0};
zOrder.push_back(windowId);
cout << "Created window " << windowId << " at ";
cout << left << ", " << top << ", " << right << ", " << bottom << '\n';
windowId++;
}
void redraw() {
for (auto it = zOrder.begin(); it != zOrder.end(); it++) {
window w = windows[*it];
cout << "Window " << w.id << " at ";
if (w.fullscreen) cout << "0, 0, 1023, 1023\n";
else cout << w.left << ", " << w.top << ", " << w.right << ", " << w.bottom << '\n';
}
}
void mouseDown() {
cin >> mouseX >> mouseY;
int windowIndex = -1;
findMouse(mouseX, mouseY, mouseDownWindowId, mouseDownArea, windowIndex);
if (mouseDownWindowId != EMPTY) {
zOrder.erase(zOrder.begin() + windowIndex);
zOrder.push_back(mouseDownWindowId);
cout << "Selected window " << mouseDownWindowId << '\n';
}
isMouseDown = 1;
lastMouseX = mouseX, lastMouseY = mouseY;
}
void mouseUp() {
cin >> mouseX >> mouseY;
if (isWindowMoving) {
moveWindow(mouseDownWindowId, mouseX - lastMouseX, mouseY - lastMouseY);
isWindowMoving = 0;
} else {
if (mouseDownArea == MOTION_BAR) {
if (!windows[mouseDownWindowId].fullscreen) moveWindow(mouseDownWindowId, mouseX - lastMouseX, mouseY - lastMouseY);
} else {
int mouseUpArea, mouseUpWindowId, windowIndex = -1;
findMouse(mouseX, mouseY, mouseUpWindowId, mouseUpArea, windowIndex);
if (mouseDownWindowId == mouseUpWindowId && mouseDownWindowId != EMPTY) {
if (mouseDownArea == mouseUpArea) {
if (mouseUpArea == CLOSE_BOX) {
windows.erase(mouseUpWindowId);
zOrder.erase(zOrder.begin() + windowIndex);
cout << "Closed window " << mouseUpWindowId << '\n';
} else if (mouseUpArea == ZOOM_BOX) {
if (windows[mouseUpWindowId].fullscreen) {
windows[mouseUpWindowId].fullscreen = 0;
cout << "Resized window " << mouseUpWindowId << " to ";
displayWindow(mouseUpWindowId);
} else {
windows[mouseUpWindowId].fullscreen = 1;
cout << "Resized window " << mouseUpWindowId << " to ";
cout << "0, 0, 1023, 1023\n";
}
}
}
}
}
}
isMouseDown = 0;
}
void mouseMove() {
cin >> mouseX >> mouseY;
if (isMouseDown && mouseDownArea == MOTION_BAR) {
if (!windows[mouseDownWindowId].fullscreen) {
moveWindow(mouseDownWindowId, mouseX - lastMouseX, mouseY - lastMouseY);
isWindowMoving = 1;
}
}
lastMouseX = mouseX, lastMouseY = mouseY;
}
int main() {
cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
string action;
while (cin >> action) {
if (action == "ZZ") break;
if (action == "CR") { createWindow(); continue; }
if (action == "RE") { redraw(); continue; }
if (action == "DN") { mouseDown(); continue; }
if (action == "UP") { mouseUp(); continue; }
if (action == "AT") { mouseMove(); continue; }
}
return 0;
}


5504

被折叠的 条评论
为什么被折叠?



