1. 题目 Punch
“在逃离诺莫瑞根的时候,我们留下了太多的数据!非常重要的数据!”大机械师卡斯派普十分着急地说,“尽管我们已经从矩阵打孔计算机上拿回了许多彩色穿孔卡片,但是混乱的数据令人无法忍受!”
自从诺莫瑞根陷落以后,侏儒们一直寄居在铁炉堡中。大机械师卡斯派普花了不少钱来悬赏勇士们去诺莫瑞根替他取回一些卡片,现在他已经有了一大堆彩色穿孔卡片。但是这些卡片都是残缺不全的,有的甚至还是无效的,想从这些破烂中恢复数据,实在是一件不容易的事。卡斯派普发现每个卡片的开头和结尾都有标记,记录着它原本在矩阵打孔计算机中序列的位置,于是想出了一个恢复数据的方法。把每张卡片看成数轴上的一条线段,开头和结尾的标记A,B为数轴上的两个点。卡斯派普按拿到的顺序把卡片一张一张地贴到数轴上,每张卡片的颜色都不同。他想知道贴完卡片以后的数轴上一共有多少种不同的颜色。卡斯派普请你帮助他写一个程序来解决这个问题。
输入格式
l 第1行:一个整数N,表示卡斯派普收集到的卡片的数量。
l 第2行至第N+1行:第i+1行给出了第i张卡片的头尾两个标记Ai,Bi,贴卡片的顺序与输入文件中出现的先后顺序一致。
输出格式
l 一个整数,表示卡斯派普能在数轴上看到的不同的颜色的数目。
样例输入
4
0 5
3 8
5 6
4 7
样例输出
3
2. 题目实质
话说,这一道是正宗的浮水法。
3. 题目来源 Leve
4. 算法
浮水法,没有悬念。
不过这里比较简单,只需要记录某一个线段是不是(或者是有一部分)浮到了最上面。
上浮思想:设竖直平面中存在有一些高度不同的线段,当一个线段上方没有被其他线段挡着时,这个线段就可以上浮,如果一个线段(或是它的一部分)可以上浮到无限高,那么显然,这个线段(或这一部分)所在的高度是他所覆盖的这一个数轴范围内(将平面的无限低的地方看做有一个数轴)最高的。
浮水法其实是一个递归的过程,首先,当一条线段满足上浮的条件时,让他上浮(用 while 循环控制),但是当他不满足上浮的条件时,将他被挡住的那一段切掉,然后接着递归的让他剩下的那部分上浮。
一开始要用排序进行预处理。
因为有高度为零的情况,所以可以一开始先在最底部画一条线段,使这一条线段的初始高度为零,这样应该为零的地方是上浮不起来的。
5. 注意事项
把这个题拿出来主要是想展示一下浮水法的框架。
然后,浮水法也可以用来求面积(横着切完竖着切,不过巨麻烦,详见usaco 3.1.4 形成的区域)。
最后,线段类问题都可以套一下浮水法。
6. 时空复杂度
因为是递归,所以不会分析。
7. 程序代码
Leve (Pascal)
var
x,y:array[0..10000] of longint;
v:array[0..100000] of boolean;
n,i,ans:longint;
procedure cut(xx,yy,t:longint);
begin
if v[i] then exit;
while(t<=n)and((yy<=x[t])or(xx>=y[t])) do inc(t);
if t>n then
begin
inc(ans);
v[i]:=true;
end;
if(xx<x[t])and(yy>x[t]) then cut(xx,x[t],t+1);
if(xx<y[t])and(yy>y[t]) then cut(y[t],yy,t+1);
end;
begin
assign(input,'punch.in');reset(input);
assign(output,'punch.out');rewrite(output);
readln(n);
ans:=1;
for i:=1 to n do
readln(x[i],y[i]);
for i:=n-1 downto 1 do
cut(x[i],y[i],i+1);
writeln(ans);
close(input);close(output);
end.