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) 不屬於任何視窗。
2.題解
2.1 陣列順序->層級關係
思路
這題我們很容易知道,只要操作點選的座標位於某個視窗限制的座標之內,那麼我們就可以判定是選中了這個視窗;
難點是在視窗之間存在重疊關係,我們如何知道選中的是那個視窗? 選中之後該視窗層級提升到最高層,又如何更新該層級關係?
這裡我們巧妙利用陣列順序儲存了視窗之間的層級關係
據題意,剛開始時的輸入順序就是視窗的初始層級關係,越往後輸入的層級越高.
所以在第一次操作點選的時候,我們選擇點選最外層的視窗,也就是我們可以選擇從外向內遍歷(對於陣列順序來說,就是倒序遍歷),如果存在符合項,即輸出其編號
同時,我們將該陣列元素轉移到最外層層級(也就是陣列pos[n-1]),具體做法就是使用erase將這個元素從陣列中刪除,然後再新增到末尾即可
由於這裡我們移動了元素,必然需要單獨儲存原來的編號值,所以除了座標外,我們還需要單獨儲存每個視窗的編號值
程式碼
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<vector<int>> pos(n, vector<int>(5));
// 初始化位置陣列
for(int i = 0; i < n; i++){
for(int j = 0; j < 4; j++){
cin >> pos[i][j];
}
pos[i][4] = i + 1; // 記錄編號
}
// 進行點選操作
for(int i = 0; i < m; i++){
int x, y, idx;
cin >> x >> y;
for(idx = n - 1; idx >= 0; idx--){
int x1 = pos[idx][0], y1 = pos[idx][1], x2 = pos[idx][2], y2 = pos[idx][3];
if((x <= x2 && x >= x1) && (y <= y2 && y >= y1)){
cout << pos[idx][4] << endl;
vector<int> temp = pos[idx];
pos.erase(pos.begin() + idx); // 刪除第 idx 個元素(這裡不要想著需要-1,因為begin是從0開始的,所以當前下標對應的總個數本來就要+1,和這個-1抵消掉了)
pos.push_back(temp); // 將儲存的元素新增到末尾
break;
}
}
if(idx < 0) cout << "IGNORED" << endl;
}
return 0;
}