poj 1177 picture
题目链接: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的更多相关文章
- POJ 1177 Picture(线段树:扫描线求轮廓周长)
题目链接:http://poj.org/problem?id=1177 题目大意:若干个矩形,求这些矩形重叠形成的图形的轮廓周长. 解题思路:这里引用一下大牛的思路:kuangbin 总体思路: 1. ...
- POJ 1177 Picture(线段树 扫描线 离散化 求矩形并面积)
题目原网址:http://poj.org/problem?id=1177 题目中文翻译: 解题思路: 总体思路: 1.沿X轴离散化建树 2.按Y值从小到大排序平行与X轴的边,然后顺序处理 如果遇到矩形 ...
- poj 1177 Picture(线段树周长并)
题目链接:http://poj.org/problem?id=1177 题意:给你n个矩形问你重叠后外边缘总共多长. 周长并与面积并很像只不过是处理的时候是 增加的周长=abs(上一次的线段的长度 ...
- HDU 1828 / POJ 1177 Picture (线段树扫描线,求矩阵并的周长,经典题)
做这道题之前,建议先做POJ 1151 Atlantis,经典的扫描线求矩阵的面积并 参考连接: http://www.cnblogs.com/scau20110726/archive/2013/0 ...
- HDU 1828 POJ 1177 Picture
矩形周长并 POJ上C++,G++都能过,HDU上C++过了,G++WA ,不知道为什么 #include<cstdio> #include<cstring> #include ...
- HDU 1828 / POJ 1177 Picture --线段树求矩形周长并
题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 ...
- POJ 1177 Picture(求周长并)
题目链接 看的HH的题解..周长有两部分组成,横着和竖着的,横着通过,sum[1] - last来计算,竖着的通过标记,记录有多少段. #include <cstdio> #include ...
- poj 1177 Picture (线段树 扫描线 离散化 矩形周长并)
题目链接 题意:给出n个矩形,每个矩形给左下 和 右上的坐标,求围成的周长的长度. 分析: 首先感谢大神的博客,最近做题经常看大神的博客:http://www.cnblogs.com/kuangbin ...
- poj 1177 --- Picture(线段树+扫描线 求矩形并的周长)
题目链接 Description A number of rectangular posters, photographs and other pictures of the same shape a ...
随机推荐
- Scala学习文档-列表的使用
注:列表是不可变的,不能通过赋值改变列表的元素 列表具有递归结构,数组是连续的 scala里的列表类型是协变的? --> scala中的逆变与协变 分治原则 //自定义实现:::操作符 def ...
- sublime 插件 和free 注册码
代码对齐: Alignment html代码补全: Emmet CoffeeScript语法: Better CoffeeScript css格式化: CSS Format less语法: L ...
- 【iOS开发】单例模式设计(ARC & MRC)
适用于ARC & MRC // 帮助实现单例设计模式 // .h文件的实现 #define SingletonH(methodName) + (instancetype)shared##met ...
- 100个iOS开发/设计程序员面试题汇总,你将如何作答?
100个iOS开发/设计程序员面试题汇总,你将如何作答? 雪姬 2015-01-25 19:10:49 工作职场 评论(0) 无论是对于公司还是开发者或设计师个人而言,面试都是一项耗时耗钱的项目, ...
- mysql 命令行 自动补全
配置文件中 默认关闭自动补全: [mysql] #no-auto-rehash # faster start of mysql but no tab completition 改为: [mysql] ...
- 自己实现的简单MVC框架(类似Struts2+Spring)
一.框架简介 本框架是一个类似于Struts2+Spring的框架,目的在于个人钻研和技术分享,将流行技术框架Struts2.Spring中使用到的主要技术以较为简化的方式实现出来,给大家一个更直观的 ...
- c++ 08
一.程序的错误 1.编码错误:编译阶段 2.设计错误:测试阶段 3.环境错误:使用阶段 4.应用错误:测试和使用阶段 二.错误处理机制 1.通过返回值处理错误 当一个函数在执行过程中发生了某种错误,通 ...
- 高精度快速幂(Java版)
import java.io.*; import java.math.*; import java.util.*; import java.text.*; public class Main { pu ...
- WPF发布程序后未授予信任的解决办法
WPF发布程序后未授予信任的解决办法 基于浏览器的WPF应用程序由于需要比较高的操作权限,所以在项目的安全性属性中选择了“这是完全可信的应用程序”选项.可是,在发布部署后,在其他电脑上打开xbap文件 ...
- Deep Compression Compressing Deep Neural Networks With Pruning, Trained QuantizationAnd Huffman Coding
转载请注明出处: http://www.cnblogs.com/sysuzyq/p/6200613.html by 少侠阿朱