poj 1151

分类: 线段树

题意: 求矩阵面积并

输入: 矩阵个数N,每个矩阵的左下角坐标和右上角坐标

输出: 矩阵的面积并

很久没有做数据结构了,这道题算是比较经典,难度相对适中的吧,今天拿出来写了一遍。数据结构主要是线段树。虽然写过几次了,每次动手写都会遇到一些问题。做个笔记:

1.基本算法:

将矩形沿着Y方向的平行于X轴的线作为扫描线。核心算法在于对于n – 1条扫描线作的高度差用来算矩阵的面积

1151_1

1151_2

上面两张是比较好理解的图(来自网络)。线段树的作用就在于保存当前的X轴覆盖区域的长度为多少,每一次,顺着扫描方向,插入一段扫描线更新当前的覆盖区域长度(会有重合)。

一个技巧:把下边的边flag设置为true,上面的边设置为false,然后在线段树中记录有多少个覆盖记录,以方便计算

2.去重与排序

可以用STL的unique,当然也可以手写,排序也是不可缺少的,本题数据量而言,时间复杂度是完全可以满足的

3.二分查找

一种映射关系,因为x坐标是浮点数,所以不可以直接离散化,需要一种映射

4.树的写法

node需要携带什么信息?如何建树和存储?

重点中的重点:插入线段的时候应该如何处理?

                            如何更新?

 

  1 #include <iostream>
  2 #include <vector>
  3 #include <map>
  4 #include <list>
  5 #include <set>
  6 #include <deque>
  7 #include <stack>
  8 #include <queue>
  9 #include <algorithm>
 10 #include <cmath>
 11 #include <cctype>
 12 #include <cstdio>
 13 #include <iomanip>
 14 #include <cmath>
 15 #include <cstdio>
 16 #include <iostream>
 17 #include <string>
 18 #include <sstream>
 19 #include <cstring>
 20 #include <queue>
 21 using namespace std;
 22 
 23 ///宏定义
 24 const int  INF = 990000000;
 25 const int MAXN = 2000;
 26 const int maxn = MAXN;
 27 ///全局变量 和 函数
 28 
 29 struct line
 30 {
 31     double ypos;
 32     double xleftPos, xrightPos;
 33     bool flag;
 34     bool operator < (const line& l)
 35     {
 36         return ypos < l.ypos;
 37     }
 38 };
 39 
 40 struct node
 41 {
 42     int lchild, rchild;
 43     int ll, rr;
 44     double length;
 45     int cover;
 46 };
 47 double xpos[maxn];
 48 
 49 void buildTree(int left, int right, int cur, node* T)
 50 {
 51     T[cur].ll = left;
 52     T[cur].rr = right;
 53     T[cur].length = 0;
 54     if (right - left == 1)
 55     {
 56         T[cur].lchild = T[cur].rchild = -1;
 57         return;
 58     }
 59     T[cur].lchild = 2 * cur;
 60     T[cur].rchild = 2 * cur + 1;    
 61     int mid = (left + right) / 2;
 62     buildTree(left, mid, 2 * cur, T);
 63     buildTree(mid, right, 2 * cur + 1, T);
 64 }
 65 node tree[maxn * 4];
 66 
 67 line lines[maxn];
 68 
 69 void update(node* T, int cur, bool flag)
 70 {
 71     if (T[cur].lchild == -1 && T[cur].rchild == -1)
 72     {
 73         int L = T[cur].ll;
 74         int R = T[cur].rr;
 75         if (flag)
 76         {
 77             T[cur].cover++;
 78             if (T[cur].cover == 1)
 79             {
 80                 T[cur].length += xpos[R - 1] - xpos[L - 1];  //注意xpos数组的下标 
 81             }            
 82         }
 83         else if(!flag)
 84         {
 85             T[cur].cover--;
 86             if (T[cur].cover == 0)
 87             {
 88                 T[cur].length -= xpos[R - 1] - xpos[L - 1];  //注意xpos数组的下标
 89             }            
 90         }
 91         return;
 92     }
 93     else
 94         T[cur].length = T[cur * 2].length + T[cur * 2 + 1].length;
 95 }
 96 void insert(node* T, int cur, int Left, int Right, bool flag)
 97 {
 98     if (T[cur].lchild == -1 && T[cur].rchild == -1)
 99     {
100 
101     }
102     else
103     {
104         int mid = (T[cur].ll + T[cur].rr) / 2;
105         if (Right <= mid)
106         {    
107             insert(T, cur * 2, Left, Right, flag);
108         }
109         else if (Left >= mid)
110         {
111             insert(T, cur * 2 + 1, Left, Right, flag);
112         }
113         else
114         {
115             insert(T, cur * 2, Left, mid, flag);
116             insert(T, cur * 2 + 1, mid, Right, flag);
117         }
118     }
119     update(T, cur, flag);
120 }
121 
122 int b_search(double *arr, int n, double val);
123 int main()
124 {
125     ///变量定义
126     int n;
127     int cases = 1;
128     while (scanf("%d", &n) && n != 0)
129     {
130         double area = 0;
131         memset(tree, 0, sizeof(tree));
132         int lineNum = 0;
133         int xposNum = 0;
134         for (int i = 0; i < n; i++)
135         {
136             double x1, y1, x2, y2;
137             scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
138             lines[lineNum].ypos = y1;
139             lines[lineNum].xleftPos = x1;
140             lines[lineNum].xrightPos = x2;
141             lines[lineNum].flag = true;
142             lineNum++;
143 
144             lines[lineNum].ypos = y2;
145             lines[lineNum].xleftPos = x1;
146             lines[lineNum].xrightPos = x2;
147             lines[lineNum].flag = false;
148             lineNum++;
149 
150             xpos[xposNum++] = x1;
151             xpos[xposNum++] = x2;
152         }
153         sort(lines, lines + lineNum);
154         sort(xpos, xpos + xposNum);
155         int k = 0;
156         for (int i = 1; i < xposNum; i++)
157         {
158             if (xpos[i] != xpos[k])
159             {
160                 xpos[++k] = xpos[i];
161             }
162         }
163         xposNum = k + 1;
164         sort(xpos, xpos + xposNum);
165 
166         //建立线段树
167         buildTree(1, xposNum, 1, tree);
168 
169         for (int i = 0; i < lineNum - 1; i++)
170         {
171             //找到下标
172             int ll = b_search(xpos, xposNum, lines[i].xleftPos);
173             int rr = b_search(xpos, xposNum, lines[i].xrightPos);
174             bool flag = lines[i].flag;
175             //插入到线段树
176             insert(tree, 1, ll + 1, rr + 1, flag);            
177 
178             //
179             area += (lines[i + 1].ypos - lines[i].ypos) * tree[1].length;
180         }
181         printf("Test case #%d\n", cases++);
182         printf("Total explored area: %.2f\n\n", area);
183     }
184 
185     ///结束
186     return 0;
187 }
188 
189 int b_search(double *arr, int n, double val)
190 {
191     int low = 0;
192     int high = n - 1;
193     int mid;
194     while (low <= high)
195     {
196         mid = (low + high) >> 1;
197         if (arr[mid] == val)
198         {
199             return mid;
200         }
201         else if (arr[mid] > val)
202         {
203             high = mid - 1;
204         }
205         else
206         {
207             low = mid + 1;
208         }
209     }
210     return -1;
211 }

 

 

 

posted on 2013-09-16 09:13  小书包_Ray  阅读(228)  评论(0编辑  收藏  举报

导航