解题报告 Figure of the city
1. 题目 Figure of the city
题目描述
60 B.C.
Latium省的Genoa是亚平宁半岛西海岸北端的一片土地,自然资源丰富,却无人居住。你受到罗马执政官Caesar的委任,前往Genoa建立新的城市。Caesar对这次任务的要求是在Genoa这片土地上建立起一座繁荣的城市,他将以此作为衡量你的表现的标准。
正在你大刀阔斧地进行城市建设的时候,Caesar突然写信给你,说他要检查Genoa的建设情况。Caesar希望知道你的城市是什么样子,但是他又非常的忙,所以他只要你描述一下城市的轮廓就可以了,他将依照城市的轮廓决定你的薪水。
怎样描述一个城市的轮廓呢?我们知道Genoa所有的建筑共享一个地面,你可以认为它是水平的。所有的建筑用一个三元组(Li,Hi,Ri)其中Li和Ri分别是建筑的左坐标和右坐标,Hi就是建筑的高度。在下方所示的图表中左边建筑物描述如下(1,11,5),(2,6,7),(3,13,9),(12,7,16),(14,3,25),(19,18,22),(23,13,29),(24,4,28),右边用轮廓线的顺序(1,11,3,13,9,0,12,7,16,3,19,18,22,3,23,13,29,0)表示:
输入数据
在输入数据中,你将得到一系列表示建筑的三元组。在输入数据中所有建筑的坐标中的数值都是小于10000的正整数,且至少有1幢建筑,最多有5,000幢建筑。在输入输入中每幢建筑的三元组各占一行。三元组中的所有整数应由一个或多个空格分开。
输出数据
在输出数据中,你被要求给出城市的轮廓线。你可以这样来描述:对于所有轮廓线上的折点,按顺序排好,第奇数个点输出x坐标,第偶数个点输出y坐标,两个数之间用空格分开。
样例输入
1 11 5
2 6 7
3 13 9
12 7 16
14 3 25
19 18 22
23 13 29
24 4 28
样例输出
1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0
2. 题目来源 又开始集训了
3. 算法
这里主要介绍两种算法:浮水法、直接模拟。
首先说一下直接模拟。这是 Leve 的解法。
每次读入的时候,直接更新这一个点(在这个楼包括范围内的点)的最高的一个值,记录为这一个点的高度。边读边处理(当每读入一个楼的时候,枚举每一个在这个楼的范围内的点,如果没有这个楼高,则更新这个点),读完之后直接输出,注意输出的时候是输出横坐标还是纵坐标。
其实这个题这么看才像是第一题。
然后浮水法,是 Ray 想到的。
上浮思想:设竖直平面中存在有一些高度不同的线段,当一个线段上方没有被其他线段挡着时,这个线段就可以上浮,如果一个线段(或是它的一部分)可以上浮到无限高,那么显然,这个线段(或这一部分)所在的高度是他所覆盖的这一个数轴范围内(将平面的无限低的地方看做有一个数轴)最高的。
然后再看这个题,将图形的竖直的线段都扒掉,那么剩下的就是一些浮在空中的线段,所以可以用浮水法。(实际上一般的像这样的线段类问题都可以用浮水法)
浮水法其实是一个递归的过程,首先,当一条线段满足上浮的条件时,让他上浮(用 while 循环控制),但是当他不满足上浮的条件时,将他被挡住的那一段切掉,然后接着递归的让他剩下的那部分上浮。
一开始要用排序进行预处理。
因为有高度为零的情况,所以可以一开始先在最底部画一条线段,使这一条线段的初始高度为零,这样应该为零的地方是上浮不起来的。
4. 注意事项
注意这一句话:
对于所有轮廓线上的折点,按顺序排好,第奇数个点输出x坐标,第偶数个点输出y坐标,两个数之间用空格分开。
那个输出,输出的不是每一个拐点的横坐标 & 纵坐标(这样还得进行特判,需要个一个点输出一个坐标,理论上讲也能输出数据,但是巨麻烦),而是横坐标 || 纵坐标。
审题是关键。
5. 时空复杂度
直接模拟是 O(n)
浮水法用到了递归,不好估计,不过放心,不会超时也不会爆栈。
6. 程序代码
模拟:Leve (Pascal)
var
h:array[1..10000] of longint;
x,y,i,hh,min,max:longint;
begin
assign(input,'input.txt');
assign(output,'output.txt');
reset(input);
rewrite(output);
min:=maxlongint;
max:=0;
while not eof do
begin
readln(x,hh,y);
if x<min then min:=x;
if y>max then max:=y;
for i:=x to y-1 do
if h[i]<hh then
h[i]:=hh;
end;
i:=min;
while i<=max do
begin
write(i,' ');
write(h[i],' ');
while (h[i+1]=h[i]) and (i<=max) do inc(i);
inc(i);
end;
close(input);
close(output);
end.
上浮:Ray (Pascal)
var
lb,al,la,i,n,m,minl,maxr:longint;
f,l,r,h:array[0..10010] of longint;
v:array[0..10010] of boolean;
procedure doing(x,y,t:longint);
begin
if v[i] then exit;
while (t>0)and((l[t-1]>y)or(r[t-1]<=x)) do dec(t);
if t<=0 then
begin
f[x]:=h[i];
exit;
end;
if l[t-1]>x then doing(x,l[t-1]-1,t-1);
if r[t-1]<=y then doing(r[t-1],y,t-1);
end;
procedure qsort(ll,rr:longint);
var
i,j,x,y:longint;
begin
i:=ll;j:=rr;x:=h[(ll+rr)>>1];
repeat
while h[i]>x do inc(i);
while x>h[j] do dec(j);
if not(i>j) then
begin
y:=h[i];h[i]:=h[j];h[j]:=y;
y:=l[i];l[i]:=l[j];l[j]:=y;
y:=r[i];r[i]:=r[j];r[j]:=y;
inc(i);dec(j);
end;
until(i>j);
if i<rr then qsort(i,rr);
if ll<j then qsort(ll,j);
end;
begin
assign(input,'input.txt');
reset(input);
assign(output,'output.txt');
rewrite(output);
minl:=20000;
maxr:=-1;
fillchar(f,sizeof(f),255);
while not eof do
begin
inc(m);
readln(l[m],h[m],r[m]);
if l[m]<minl then minl:=l[m];
if r[m]>maxr then maxr:=r[m];
end;
qsort(1,m);
inc(m);l[m]:=minl;r[m]:=maxr;h[m]:=0;
f[l[1]]:=h[1];
for i:=2 to m do
begin
doing(l[i],r[i],i);
v[i]:=true;
end;
for i:=minl to maxr do
if f[i]<>-1 then write(i,' ',f[i],' ');
close(input);
close(output);
end.
7. 囧囧的阿相:
话说,受某 oj 上得某个 BT 的某道题(跌落的世界、立体图。。。神马的)的影响,本人一看到图形题就发虚,其实图形题不一定有多难。