序列DP:线段覆盖
题目描述Description
给定x轴上的N(0<N<100)条线段,每个线段由它的二个端点a_I和b_I确定,I=1,2,……N.这些坐标都是区间(-999,999)的整数。有些线段之间会相互交叠或覆盖。请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段两两之间没有内部公共点。所谓的内部公共点是指一个点同时属于两条线段且至少在其中一条线段的内部(即除去端点的部分)。
输入描述 Input Description
输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。
输出描述 Output Description
输出第一行是一个整数表示最多剩下的线段数。
样例输入 Sample Input
3
6 3
1 3
2 5
样例输出 Sample Output
2
数据范围及提示Data Size & Hint
0<N<100
从一开始做这道题,别人就告诉我说,要用贪心,我就是始终理解不了贪心的奥秘。
so,就用DP来做这道题吧。
读入:这一点特别坑,读入时起点可能大于终点
所以要判断大小。
在处理数据之前,要根据起点排序。
用a[i]来表示起点,b[i]来表示终点
f[i]代表在第i条线段之前最多有多少条可剩下的线段
当0<j<i时,如果a[i]>=b[j]{题目中说,可以存在边缘公共点}
则得到状态转移方程:f[i]:=max(f[j]}+1;{0<j<i}
var n:longint;{线段个数}
a{起点},b{终点}:array[1..100]of longint;
f:array[1..100]of longint;{最多剩下的线段数}
i,j,k:longint;
findmax:longint;
function min(x,y:longint):longint;
begin if x>y
then exit(y)
else exit(x);
end;
function max(x,y:longint):longint;
begin if x>y
then exit(x)
else exit(y);
end;
procedure qsort(s,t:longint);
var head,tail,k,temp1,temp2:longint;
begin head:=s; tail:=t;
k:=a[(head+tail) div 2];
while head<tail do
begin while a[head]<k do inc(head);
while k<a[tail] do dec(tail);
if head<=tail
then begin temp1:=a[head];
a[head]:=a[tail];
a[tail]:=temp1;
temp2:=b[head];
b[head]:=b[tail];
b[tail]:=temp2;
inc(head);
dec(tail);
end;
end;
if head<t then qsort(head,t);
if s<tail then qsort(s,tail);
end;
begin
readln(n);
for i:=1 to n do
begin readln(j,k);
a[i]:=min(j,k);
b[i]:=max(j,k);
end;
qsort(1,n);
f[1]:=1;
for i:=2 to n do
begin findmax:=0;
for j:=1 to i-1 do
if (a[i]>=b[j])and (f[j]>findmax)
then findmax:=f[j];
if findmax<>0
then f[i]:=findmax+1
else f[i]:=1;
end;
findmax:=0;
for i:=1 to n do
if f[i]>findmax
then findmax:=f[i];
write(findmax);
end.