题目链接:http://poj.org/problem?id=1177

分析:这道题主要用到了线段树、扫描线以及离散化的相关算法。

离散化

离散化是当数字不多但是范围很大时采用的一种方法,将大区间的数字映射到一个小区间上,如,有一组数字:132398,12781,2342876,232,将其离散化后将得到2,1,3,0.

离散化的算法:

 //y为大小为n的数组,存放着离散化前的数
sort(y,y+n);
int unique_count=unique(y,y+n)-y;
//find_i为自己编写的根据N来寻找对应的i的函数
find_i(N);

将不同的y值离散化后建立线段树,下面为树的节点,其中,left,right为离散化的区间值,左闭右开,count为该区间被覆盖的次数,初始化为0,inter为竖直的矩形边的区间数,之后计算平行于x轴的边的周长会用到,lflag、rflag为左右端点是否被覆盖,用于计算inter,len为被覆盖长度。

struct Node{
int left, right;
int count;
int inter;
int lflag, rflag;
int len;
};

扫描线

将垂直于x轴的矩形的边作为扫描线,对其按x大小排序后逐个进行扫描,flag为0表示右边的边,flag为1表示左边的边。

struct Scan{
int x;
int y1, y2;
int flag;
};

代码如下:

 #include <iostream>
#include <algorithm>
#include <cmath> #define MAX 10000 using namespace std; struct Scan{
int x;
int y1, y2;
int flag;
};
struct Node{
int left, right;
int count;//被覆盖次数
int inter;////覆盖后的区间数量,2*line*| |
int lflag, rflag;//左右端点是否被覆盖
int len;//测度,覆盖区间的长度
}; struct Node node[ * MAX];
struct Scan scanline[ * MAX];
int y[MAX]; bool cmp(struct Scan line1, struct Scan line2);
void build(int L, int R, int i);
void insert(int L, int R, int i);
void remove(int L, int R, int i);
void update_len(int i);
void update_inter(int i); int main(){
int N;
//freopen("picture_in.txt", "r", stdin);
cin >> N;
int x1, x2, y1, y2;
int len_now = , inter_now = ;
int total_perimeter = ;
int n = ;
while (N--){
cin >> x1 >> y1 >> x2 >> y2;
y[n] = y1;
scanline[n].x = x1;
scanline[n].y1 = y1;
scanline[n].y2 = y2;
scanline[n++].flag = ;
y[n] = y2;
scanline[n].x = x2;
scanline[n].y1 = y1;
scanline[n].y2 = y2;
scanline[n++].flag = ;
}
sort(y, y + n);
sort(scanline, scanline + n, cmp);
//y数组中不重复的个数
int unique_count = unique(y, y + n) - y;
build(, unique_count - , );
for (int i = ; i<n; i++){
if (scanline[i].flag)
//左边插入
insert(scanline[i].y1, scanline[i].y2, );
//右边消除
else
remove(scanline[i].y1, scanline[i].y2, );
if (i>){
total_perimeter += * (scanline[i].x - scanline[i - ].x)*inter_now;
}
total_perimeter += abs(len_now - node[].len);
//cout << "perimeter after y:" << total_perimeter << endl;
len_now = node[].len;
inter_now = node[].inter;
//cout << "len_now:" << len_now << " inter_now:" << inter_now << endl << endl;
}
cout << total_perimeter << endl;
return ;
} bool cmp(struct Scan line1, struct Scan line2){
if (line1.x == line2.x)
return line1.flag>line2.flag;
return line1.x<line2.x;
} //创建指定区间的线段树并初始化
void build(int L, int R, int i){
node[i].left = L;
node[i].right = R;
node[i].count = ;
node[i].inter = ;
node[i].len = ;
node[i].lflag = node[i].rflag = ;
if (R - L>){
int M = (L + R) / ;
build(L, M, * i + );
build(M, R, * i + );
}
} //左边的边出现,插入记录
//不管是插入还是消除,都一直更新到根结点,即node[0]
void insert(int L, int R, int i){
if (L <= y[node[i].left] && R >= y[node[i].right])
node[i].count++;
else if (node[i].right - node[i].left == )
return;
else{
int mid = (node[i].left + node[i].right) / ;
if (R <= y[mid])
insert(L, R, * i + );
else if (L >= y[mid])
insert(L, R, * i + );
else{
insert(L, y[mid], * i + );
insert(y[mid], R, * i + );
}
}
update_len(i);
update_inter(i);
} //右边的边出现,则消除记录
//其实就是一步步退回去
void remove(int L, int R, int i){
if (L <= y[node[i].left] && R >= y[node[i].right])
node[i].count--;
else if (node[i].right - node[i].left == )
return;
else{
int mid = (node[i].left + node[i].right) / ;
if (R <= y[mid])
remove(L, R, * i + );
else if (L >= y[mid])
remove(L, R, * i + );
else{
remove(L, y[mid], * i + );
remove(y[mid], R, * i + );
}
}
update_len(i);
update_inter(i);
} void update_len(int i){
if (node[i].count>)
node[i].len = y[node[i].right] - y[node[i].left];
else if (node[i].right - node[i].left == )
node[i].len = ;
else
node[i].len = node[ * i + ].len + node[ * i + ].len;
} void update_inter(int i){
if (node[i].count>){
node[i].lflag = ;
node[i].rflag = ;
node[i].inter = ;
}
else if (node[i].right - node[i].left == ){
node[i].lflag = ;
node[i].rflag = ;
node[i].inter = ;
}
else{
node[i].lflag = node[ * i + ].lflag;
node[i].rflag = node[ * i + ].rflag;
node[i].inter = node[ * i + ].inter + node[ * i + ].inter -
node[ * i + ].rflag*node[ * i + ].lflag;
}
}

给几组测试数据:
测试数据1:

输入:

47
-1105 -1155 -930 -285
-765 -1115 -615 -375
-705 -480 -165 -285
-705 -1200 -175 -1025
-275 -1105 -105 -385
-10 -1165 185 -285
315 -1160 400 -710
340 -1195 655 -1070
580 -1140 655 -265
325 -480 395 -335
365 -390 620 -265
365 -770 610 -665
815 -1195 1110 -1070
825 -760 1100 -660
810 -405 1115 -275
780 -700 860 -360
1065 -695 1130 -360
775 -1110 860 -735
1070 -1110 1145 -730
-1065 -95 140 260
-725 80 750 460
135 -135 490 840
135 -135 490 750
-520 40 -210 945
-595 620 215 695
670 -5 855 610
550 -75 830 -25
815 240 1085 370
980 -90 1125 145
280 150 490 315
-1035 -155 -845 -90
855 815 950 1030
785 980 860 1165
945 985 1015 1160
730 835 1075 895
875 695 935 790
-1165 420 -520 650
-1090 815 -210 945
-130 800 65 1160
120 980 690 1150
-1140 995 -125 1180
-825 1050 -195 1135
-90 865 10 1090
280 1045 625 1090
-655 1065 -245 1115
-1155 70 -790 315
-1005 110 -825 225

输出:3700

测试数据2:

输入:

-10 -10 0 10

0 -10 10 10

输出:

代码是参考另一位大牛写的,原文请见:http://www.cnblogs.com/shuaiwhu/archive/2012/04/22/2464876.html,讲解非常详细

poj 1177 picture的更多相关文章

  1. POJ 1177 Picture(线段树:扫描线求轮廓周长)

    题目链接:http://poj.org/problem?id=1177 题目大意:若干个矩形,求这些矩形重叠形成的图形的轮廓周长. 解题思路:这里引用一下大牛的思路:kuangbin 总体思路: 1. ...

  2. POJ 1177 Picture(线段树 扫描线 离散化 求矩形并面积)

    题目原网址:http://poj.org/problem?id=1177 题目中文翻译: 解题思路: 总体思路: 1.沿X轴离散化建树 2.按Y值从小到大排序平行与X轴的边,然后顺序处理 如果遇到矩形 ...

  3. poj 1177 Picture(线段树周长并)

    题目链接:http://poj.org/problem?id=1177 题意:给你n个矩形问你重叠后外边缘总共多长. 周长并与面积并很像只不过是处理的时候是   增加的周长=abs(上一次的线段的长度 ...

  4. HDU 1828 / POJ 1177 Picture (线段树扫描线,求矩阵并的周长,经典题)

    做这道题之前,建议先做POJ 1151  Atlantis,经典的扫描线求矩阵的面积并 参考连接: http://www.cnblogs.com/scau20110726/archive/2013/0 ...

  5. HDU 1828 POJ 1177 Picture

    矩形周长并 POJ上C++,G++都能过,HDU上C++过了,G++WA ,不知道为什么 #include<cstdio> #include<cstring> #include ...

  6. HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

    题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 ...

  7. POJ 1177 Picture(求周长并)

    题目链接 看的HH的题解..周长有两部分组成,横着和竖着的,横着通过,sum[1] - last来计算,竖着的通过标记,记录有多少段. #include <cstdio> #include ...

  8. poj 1177 Picture (线段树 扫描线 离散化 矩形周长并)

    题目链接 题意:给出n个矩形,每个矩形给左下 和 右上的坐标,求围成的周长的长度. 分析: 首先感谢大神的博客,最近做题经常看大神的博客:http://www.cnblogs.com/kuangbin ...

  9. poj 1177 --- Picture(线段树+扫描线 求矩形并的周长)

    题目链接 Description A number of rectangular posters, photographs and other pictures of the same shape a ...

随机推荐

  1. 每次从vss获取文件都是只读

    在 Visual Studio 2008 中,使用 VSS 作为源码管理器,把文件签入后,文件会自动变为只读状态.在公司习惯是在某个开发人员的机器上获取最新的代码后编译,编译完之后服务器上再从 VSS ...

  2. jquery中ajax的dataType属性包括哪几项

    参考ajax api文档:http://www.w3school.com.cn/jquery/ajax_ajax.asp dataType类型:String预期服务器返回的数据类型.如果不指定,jQu ...

  3. NFine常见错误

    1.新增数据录入录入不进去提示:An error occurred while updating the entries.See the inner exception for details. 这样 ...

  4. U盘启动时无USB-HDD选项的解决方案

    今天在使用一块老板子的时候 发现没有USB-HDD启动项 在启动顺序中只有 USB-ZIP(ZIP)  -FDD(软盘) -CDROM(光驱) 1.插入U盘 2.开机 3.在BIOS中找到Hard D ...

  5. IOS 面试 --- 网络部分

    网络部分 3 做过的项目是否涉及网络访问功能,使用什么对象完成网络功能? 答案:ASIHTTPRequest与NSURLConnection 4 简单介绍下NSURLConnection类及+ sen ...

  6. Effective Java2读书笔记-类和接口(四)

    第19条:接口只用于定义类型 这一条就举了一个反例,说有些接口中只包含常量.这是对接口的不良使用.要实现相同的功能,应该使用不可实例化的工具类(第4条说过). public class Physica ...

  7. 数据结构之顺序表,c#实现

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  8. Asp.net MVC中的ViewData与ViewBag(转)

    在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下: ViewData ViewBag 它是Key/Value字典集合 它是dynamic类型对像 从 ...

  9. Zigzag Iterator 解答

    Question Given two 1d vectors, implement an iterator to return their elements alternately. For examp ...

  10. javascript 我是广告

    <!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equ ...