征战蓝桥 —— 2017年第八届 —— C/C++A组第10题——油漆面积
題目
X星球的一批考古機器人正在一片廢墟上考古。
該區域的地面堅硬如石、平整如鏡。
管理人員為方便,建立了標準的直角坐標系。
每個機器人都各有特長、身懷絕技。它們感興趣的內容也不相同。
經過各種測量,每個機器人都會報告一個或多個矩形區域,作為優先考古的區域。
矩形的表示格式為(x1,y1,x2,y2),代表矩形的兩個對角點坐標。
為了醒目,總部要求對所有機器人選中的矩形區域涂黃色油漆。
小明并不需要當油漆工,只是他需要計算一下,一共要耗費多少油漆。
其實這也不難,只要算出所有矩形覆蓋的區域一共有多大面積就可以了。
注意,各個矩形間可能重疊。
本題的輸入為若干矩形,要求輸出其覆蓋的總面積。
輸入格式:
第一行,一個整數n,表示有多少個矩形(1<=n<10000)
接下來的n行,每行有4個整數x1 y1 x2 y2,空格分開,表示矩形的兩個對角頂點坐標。
(0<= x1,y1,x2,y2 <=10000)
輸出格式:
一行一個整數,表示矩形覆蓋的總面積面積。
例如,
輸入:
3
1 5 10 10
3 1 20 20
2 7 15 17
程序應該輸出:
340
再例如,
輸入:
3
5 2 10 6
2 7 12 10
8 1 15 15
程序應該輸出:
128
資源約定:
峰值內存消耗(含虛擬機) < 256M
CPU消耗 < 2000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入…” 的多余內容。
注意:
main函數需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要調用依賴于編譯環境或操作系統的特殊函數。
所有依賴的函數必須明確地在源文件中 #include
不能通過工程設置而省略常用頭文件。
提交程序時,注意選擇所期望的語言類型和編譯器類型。
代碼
#include <stdio.h>using namespace std; int n, sum = 0; bool p[10005][10005];void paint(int x1, int y1, int x2, int y2) {for (int i = x1; i < x2; i++) {for (int j = y1; j < y2; j++) {p[i][j] = 1;}} }int main(int argc, const char *argv[]) {scanf("%d", &n);for (int i = 0; i < n; i++) {int x1, y1, x2, y2;scanf("%d %d %d %d", &x1, &y1, &x2, &y2);paint(x1, y1, x2, y2);}for (int i = 0; i < 10005; i++) {for (int j = 0; j < 10005; j++) {if (p[i][j])sum++;}}printf("%d\n", sum); } #include <stdio.h> #include <algorithm>using namespace std;/*輔助的數據結構:掃描線*/ struct Line {int x1, x2, h, f;//左右坐標,縱坐標(高度),f=1為入邊,f=-1為出邊Line() {}Line(int _l, int _r, int _h, int _f) : x1(_l), x2(_r), h(_h), f(_f) {}/*按高度排序*/bool operator<(const Line &l) const {return h < l.h;} };/*線段樹的定義*/ struct SegTree {int pl, pr, cnt, len;//左端點編號,右端點編號,被覆蓋次數,兩個端點之間被覆蓋的長度SegTree() : cnt(0), len(0) {}SegTree *lson, *rson; };const int N = 10000; int n; int X[N << 1];//記錄所有的橫坐標 //int PL=0,PR; Line lines[N];/*構建區間樹*/ SegTree *buildTree(int pl, int pr) {SegTree *t = new SegTree();t->pl = pl;t->pr = pr;if (pl == pr)return t;int mid = ((pl + pr) >> 1);t->lson = buildTree(pl, mid);t->rson = buildTree(mid + 1, pr);return t; }void updateLength(SegTree *pTree, int tl, int tr) {if (pTree->cnt) {pTree->len = X[tr] - X[tl-1];//將區間樹上的端點(序號)反入到X中求得二維坐標上的實際橫坐標} else if (tl == tr) {pTree->len = 0;} else {//負數pTree->len = pTree->lson->len + pTree->rson->len;}}void update(SegTree *tree, int pl, int pr, int value) {int tl = tree->pl;int tr = tree->pr;if (pl <= tl && pr >= tr) {tree->cnt += value;updateLength(tree, tl, tr);return;;}int m = (tl + tr) >> 1;if (pl <= m) update(tree->lson, pl, pr, value);if (pr > m) update(tree->rson, pl, pr, value);updateLength(tree, tl, tr);}int ans;int main(int argc, const char *argv[]) {scanf("%d", &n);int x1, y1, x2, y2;int index = 0;for (int i = 0; i < n; i++) {scanf("%d %d %d %d", &x1, &y1, &x2, &y2);X[index] = x1;lines[index] = Line(x1, x2, y1, 1);//高度1index++;X[index] = x2;lines[index] = Line(x1, x2, y2, -1);//高度2index++;} // 大體上就有了2n個橫坐標,2n條水平線段sort(X, X + index);//所有橫坐標點排序sort(lines, lines + index);//掃描線排序,從低到高/*離散化橫坐標*/int X_end = unique(X, X + index) - X;//去重返回值是一個迭代器,它指向的是去重后容器中不重復序列的最后一個元素的下一個元素 // PR=X_end; // 初始化線段樹SegTree *root = buildTree(1, X_end); // 從低到高,遍歷掃描線for (int i = 0; i < index; ++i) {int pl = lower_bound(X, X + X_end, lines[i].x1) - X;//二分查找,記錄下標,代表是第幾個點int pr = lower_bound(X, X + X_end, lines[i].x2) - X;//二分查找,記錄下標,代表是第幾個點update(root, pl+1, pr, lines[i].f);ans += root->len * (lines[i + 1].h - lines[i].h);//寬度*高度}printf("%d\n", ans);return 0; } 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的征战蓝桥 —— 2017年第八届 —— C/C++A组第10题——油漆面积的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017年第八届蓝桥杯 - 省赛 - C
- 下一篇: 征战蓝桥 —— 2017年第八届 ——