[洛谷P2745] [USACO5.3]窗體面積Window Area
洛谷題目鏈接:[USACO5.3]窗體面積Window Area
題目描述
你剛剛接手一項窗體界面工程。窗體界面還算簡單,而且幸運的是,你不必顯示實際的窗體。有 5 種基本操作:
創建一個新窗體
將窗體置頂
將窗體置底
刪除一個窗體
輸出窗體可見部分的百分比(就是,不被其它窗體覆蓋的部分)。
在輸入文件中,操作以如下的格式出現。
創建一個新窗體:w(I,x,y,X,Y)
將窗體置頂: t(I)
將窗體置底: b(I)
刪除一個窗體:d(I)
輸出窗體可見部分的百分比:s(I)
I 是每個窗體唯一的標識符,標識符可以是 ‘a‘..‘z‘, ‘A‘..‘Z‘ 和 ‘0‘..‘9‘ 中的任何一個。輸入文件中沒有多余的空格。
(x,y)和(X,Y)是窗體的對角。當你創建一個窗體的時候,它自動被“置頂”。你不能用已經存在的標識符來創建窗體,但是你可以刪除一個窗體後再用已刪除窗體的標識符來創建窗體。坐標用正整數來表示,並且所有的窗體面積都不為 0(x <> X 且 y <> Y)。x 坐標和 y 坐標在 1 —— 32767 的範圍內。
輸入輸出格式
輸入格式:
輸入文件包含給你的解釋程序的一系列命令,每行一個。當輸入文件結束時,停止程序。
輸出格式:
只對於 s(I) 命令進行輸出。當然,輸入文件可能有許多 s(I) 命令(不超過500次),所以輸出文件應該是一個百分比的序列,每行一個,百分比是窗體可見部分的百分比。百分比應該四舍五入到三位小數。
輸入輸出樣例
輸入樣例#1:
w(a,10,132,20,12)
w(b,8,76,124,15)
s(a)
輸出樣例#1:
49.167
說明
題目翻譯來自NOCOW。
USACO Training Section 5.3
題解: 這裏使用了一種叫做上浮法的算法.
考慮當前要上浮的矩形在第\(k\)層,需要上升到第\(k-1\)層,那麽它上面的矩形和它只有兩種情況:相交或者不相交,顯然不相交的情況可以不用考慮,直接將它提到第\(k-1\)層就可以了.
那麽相交的情況怎麽處理呢?我們來看一下下面這張圖:
圖中藍色的是我們正在上浮的矩形\(B(blue)\),紅色的是在\(R(red)\)上面一層擋住\(B\)
那麽根據這個原理,我們就可以將正在上升的矩形分為最多\(4\)部分繼續上浮,這一過程可以用\(dfs\)來實現,具體實現看一下代碼.
void dfs(int k, int x1, int y1, int x2, int y2){
if(x1 == x2 || y1 == y2) return; // 判斷遞歸的邊界條件
if(!k){ ans += (double)(x2-x1)*(y2-y1); return; }
int a1 = a[k].x1, b1 = a[k].y1, a2 = a[k].x2, b2 = a[k].y2;
if(a2 < x1 || a1 > x2 || b2 < y1 || b1 > y2){
dfs(k-1, x1, y1, x2, y2); return; // 無交集直接繼續下一層不需要回溯
}
if(a1 <= x1 && b1 <= y1 && x2 <= a2 && y2 <= b2) return; // 已經被某個矩形完全覆蓋了那麽就不可能被看到了,直接return
dfs(k-1, x1, min(y2, b2), min(x2, a2), y2); // up
dfs(k-1, min(x2, a2), max(y1, b1), x2, y2); // right
dfs(k-1, max(x1, a1), y1, x2, max(y1, b1)); // down
dfs(k-1, x1, y1, max(x1, a1), min(y2, b2)); // left
//這裏的四個dfs就是將正在上浮的矩形分割的過程,參數可以自己畫幾個栗子模擬一下
}
知道了如何統計矩形面積,剩下的只需要模擬一下就好了.
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
// N只有100是因為窗口標識符只有大小寫字母和0到9
int used[300], cnt = 0;
double ans = 0, tot = 0;
struct window{
int x1, x2, y1, y2; char c;
window(int _x1 = 0, int _y1 = 0, int _x2 = 0, int _y2 = 0, int _c = 0){
x1 = _x1, y1 = _y1, x2 = _x2, y2 = _y2, c = _c;
}
bool operator == (const window &a) const {
return c == a.c;
}
bool operator < (const window &a) const {
if(x1 != a.x1) return x1 < a.x1;
if(y1 != a.y1) return y1 < a.y1;
if(x2 != a.x2) return x2 < a.x2;
return y2 < a.y2;
}
}a[N], win[300];
void move(window x, int f){
int pos = 0;
for(int i = 1; i <= cnt; i++)
if(a[i] == x){ pos = i; break; }
if(f == 0) for(int i = pos; i >= 2; i--) swap(a[i], a[i-1]);
else for(int i = pos; i < cnt; i++) swap(a[i], a[i+1]);
}
void delet(window x){
int pos;
for(int i = 1; i <= cnt; i++)
if(a[i] == x) pos = i;
used[x.c] = 0, win[x.c] = (window){ 0, 0, 0, 0, 0 };
for(int i = pos+1; i <= cnt; i++) a[i-1] = a[i];
cnt--;
}
void dfs(int k, int x1, int y1, int x2, int y2){
if(x1 == x2 || y1 == y2) return;
if(!k){ ans += (double)(x2-x1)*(y2-y1); return; }
int a1 = a[k].x1, b1 = a[k].y1, a2 = a[k].x2, b2 = a[k].y2;
if(a2 < x1 || a1 > x2 || b2 < y1 || b1 > y2){
dfs(k-1, x1, y1, x2, y2); return;
}
if(a1 <= x1 && b1 <= y1 && x2 <= a2 && y2 <= b2) return;
dfs(k-1, x1, min(y2, b2), min(x2, a2), y2); // up
dfs(k-1, min(x2, a2), max(y1, b1), x2, y2); // right
dfs(k-1, max(x1, a1), y1, x2, max(y1, b1)); // down
dfs(k-1, x1, y1, max(x1, a1), min(y2, b2)); // left
}
int main(){
char opt, id; int x1, y1, x2, y2, pos; window tmp;
while(cin >> opt){
if(opt == 's'){
scanf("(%c)", &id); pos = 0;
for(int i = 1; i <= cnt; i++)
if(a[i] == win[id]) pos = i;
ans = 0, tot = (double)(a[pos].x2-a[pos].x1)*(a[pos].y2-a[pos].y1);
dfs(pos-1, a[pos].x1, a[pos].y1, a[pos].x2, a[pos].y2);
cout << fixed << setprecision(3) << ans*100/tot << endl;
} else {
scanf("(%c,%d,%d,%d,%d)", &id, &x1, &y1, &x2, &y2);
if(x1 > x2) swap(x1, x2); if(y1 > y2) swap(y1, y2);
tmp = (window){ x1, y1, x2, y2, id };
if(opt == 'w'){
if(used[id]) continue;
win[id] = a[++cnt] = tmp, move(tmp, 0);
}
if(opt == 't') move(tmp, 0);
if(opt == 'b') move(tmp, 1);
if(opt == 'd') delet(tmp);
}
opt = getchar();
}
return 0;
}
[洛谷P2745] [USACO5.3]窗體面積Window Area