题解 P1183 【多边形的面积】

SIGSEGV

2018-07-10 14:46:34

Solution

~~数论看了头晕的看这里~~ dalao们用的是数学,来一发纯模拟的: 先贴一发40分代码(连样例都过不了的): ```cpp #include <bits/stdc++.h> using namespace std; int n;int a[505][505]; int t1,t2,t3,t4,dx[] = {1,0,-1,0},dy[] = {0,1,0,-1}; struct Node{int x,y;}; queue<Node> q; void bfs(int x,int y,int clr) //bfs填充 { while (!q.empty()) q.pop(); q.push({x,y}); while (!q.empty()) { Node nd = q.front();q.pop(); if (a[nd.x][nd.y]) continue; a[nd.x][nd.y] = clr; for (int i = 0;i < 4;i++) { int nx = nd.x + dx[i],ny = nd.y + dy[i]; if (nx >= 0 && nx <= 500 && ny >= 0 && ny <= 500) q.push({nx,ny}); //扩展 } } } int main () { scanf("%d",&n); int sx = 0,sy = 0; for (int i = 0;i <= n;i++) //为封口,多做一轮 { if (i != n) scanf("%d%d",&t1,&t2); else t1 = sx,t2 = sy;//else的一步用来封口 t1 += 250;t2 += 250; //t1,t2:新读进来的;t3,t4:上一步的 if (i) { if (t1 == t3) { int mv = min(t2,t4),mx = t2 + t4 - mv;//新的坐标和旧的坐标之间连线,mv为坐标较小的,mx为坐标较大的,下同 for (int i = mv;i <= mx;i++) a[t1][i] = 1; } else { int mv = min(t1,t3),mx = t1 + t3 - mv; for (int i = mv;i <= mx;i++) a[i][t2] = 1; } } else { sx = t1 - 250;sy = t2 - 250; //只读了一个点 } t3 = t1;t4 = t2;//更新旧值 } bfs(0,0,-1);//填充外面的,用-1表示 for (int i = 0;i <= 500;i++) for (int j = 0;j <= 500;j++) if (a[i][j] == 0) bfs(i,j,1);//填充里面的,用1表示 int ans = 0; for (int i = 0;i <= 500;i++) for (int j = 0;j <= 500;j++) if (a[i][j] == 1 && a[i + 1][j] == 1 && a[i][j + 1] == 1 && a[i + 1][j + 1] == 1) ++ans;//每当有2*2的一个全部由1组成的正方形出现时,面积就加1(四个1对应四个点) printf("%d\n",ans); return 0; } ``` 算法思路:将多边形的线勾出来,然后再算面积。比如对于矩阵 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 一个数字对应一个顶点,图中的图形的面积为3*3-2=7 代码的缺陷是:一些凹进去的东西会算上去: 比如 1 1 1 1 1 1 1 1 1 1 1 1 定义第x行第y列的点为(x,y),假设题目中是(1,2)到(2,2)中有一条线,(2,2)到(3,2)是一条线, (3,2)到(3,1)有一条线,则绘图效果和上面那个矩阵一样:凹进去的部分被“填补了” 解决方案为:将矩阵长宽各扩大2倍,勾线时也按原来的2倍画,最后算面积时➗4。 正解代码(相同部分的注释就不写啦): ```cpp #include <bits/stdc++.h> using namespace std; int n;int a[2005][2005]; int t1,t2,t3,t4,dx[] = {1,0,-1,0},dy[] = {0,1,0,-1},lx = 1001,ly = 1001, rx = -1,ry = -1; struct Node{int x,y;}; queue<Node> q; void bfs(int x,int y,int clr) { while (!q.empty()) q.pop(); q.push({x,y}); while (!q.empty()) { Node nd = q.front();q.pop(); if (a[nd.x][nd.y]) continue; a[nd.x][nd.y] = clr; for (int i = 0;i < 4;i++) { int nx = nd.x + dx[i],ny = nd.y + dy[i]; if (nx >= lx && nx <= rx && ny >= ly && ny <= ry) q.push({nx,ny}); } } } int main () { scanf("%d",&n); int sx = 0,sy = 0,ssx,ssy; scanf("%d%d",&sx,&sy);sx += 1001;sy += 1001;a[sx][sy] = 1;t3 = sx;t4 = sy; ssx = sx;ssy = sy;//sx,sy表示当前勾线位置 //ssx,ssy表示第一个点 lx = min(lx,ssx);ly = min(ly,ssy);rx = max(rx,ssx);ry = max(ry,ssy); //lx,ly左上角坐标,rx,ry右下角坐标,是一个优化 for (int i = 1;i <= n;i++) { if (i != n) { scanf("%d%d",&t1,&t2);t1 += 1001;t2 += 1001;//加1000刚好会RE,悲哀,我在这个地方卡了半个小时 } else t1 = ssx,t2 = ssy; if (t1 == t3) { int dis = 2 * abs(t2 - t4);//距离,下同 if (t2 < t4) { for (int i = 1;i <= dis;i++) a[sx][++sy] = 1; } else { for (int i = 1;i <= dis;i++) a[sx][--sy] = 1; } } else { int dis = 2 * abs(t1 - t3); if (t1 < t3) { for (int i = 1;i <= dis;i++) a[++sx][sy] = 1; } else { for (int i = 1;i <= dis;i++) a[--sx][sy] = 1; } } t3 = t1;t4 = t2; lx = min(lx,sx);ly = min(ly,sy);rx = max(rx,sx);ry = max(ry,sy);//更新左上角,右下角 } lx--;rx++;ly--;ry++;//将外面一圈连起来 bfs(lx,ly,-1); for (int i = lx;i <= rx;i++) for (int j = ly;j <= ry;j++) if (a[i][j] == 0) { bfs(i,j,1);break; } int ans = 0; for (int i = lx;i <= rx;i++) for (int j = ly;j <= ry;j++) if (a[i][j] == 1 && a[i + 1][j] == 1 && a[i][j + 1] == 1 && a[i + 1][j + 1] == 1) ++ans; printf("%d\n",ans / 4); return 0; } ```