POJ2374 Fence Obstacle Course——线段树+动态规划

 初次看到这道题,明显的动态规划。但是,朴素的转移方程的时间复杂度是O(n^2)的,对于n<=50000的程序根本无法承受。所以,我们要考虑优化,不谈优化到O(n),也要到O(nlogn)吧。怎么优化呢?

注意到这题有个隐含的条件:从每个栅栏往下走只能走到最多两个固定的栅栏上面:即向左拐、向右拐只能到确定的栅栏上,所以,利用线段树来维护是最好的选择。我们采用的就是线段树可以动态的更新每条线段的颜色!这样,就可以预处理出每条栅栏能够到达下面的哪条栅栏了。

具体做法:

1、线段树每条线段初始颜色pos赋为0.

2、依次询问每条线段左右端点所对应的点的颜色。插入该线段,并更改这条线段在线段树中所对应线段的颜色。

注意事项:

1、线段树中如果一条线段有多种颜色,那么将其pos值赋为-1

2、在更改pos值为-1的时候注意不要把以前插入的线段覆盖多了。比如,这个代码是错误的:

Procedure Insert_Tree(code,l,r:Longint);
var mid:Longint;
begin
	if (Tree[code].l=l)and(Tree[code].r=r)then 
		begin
			Tree[code].pos:=i;
			exit;
		end;
	mid:=(tree[code].l+tree[code].r)>>1;
	if mid>=r then Insert_Tree(code*2,l,r) else
		if mid<=l then Insert_Tree(code*2+1,l,r) else
			begin
				Insert_Tree(code*2,l,mid);
				Insert_Tree(code*2+1,mid,r);
			end;
	if (Tree[code*2].pos<>Tree[code*2+1].pos)or(Tree[code*2].pos=-1)or(Tree[code*2+1].pos=-1)then 
		Tree[code].pos:=-1 else Tree[code].pos:=Tree[code*2].pos;
end;

上面的代码会将不该全部覆盖的单色线段全部覆盖,而失去这个颜色在线段树中的记录。
具体的,多做一些线段树的题目就好了。

至于动态规划,很简单的转移方程,记忆化搜索的思想:

if f[i,0]+abs(b[i]-b[next[i,0]])<f[next[i,0],0] then f[next[i,0],0]:=f[i,0]+abs(b[i]-b[next[i,0]]);
if f[i,0]+abs(b[i]-e[next[i,0]])<f[next[i,0],1] then f[next[i,0],1]:=f[i,0]+abs(b[i]-e[next[i,0]]);
if f[i,1]+abs(e[i]-b[next[i,1]])<f[next[i,1],0] then f[next[i,1],0]:=f[i,1]+abs(e[i]-b[next[i,1]]);
if f[i,1]+abs(e[i]-e[next[i,1]])<f[next[i,1],1] then f[next[i,1],1]:=f[i,1]+abs(e[i]-e[next[i,1]]);

CODE

Program POJ2374;//By_Poetshy
Const
	maxn=50000;
Type
	rec=record
		l,r,pos:Longint;
		end;
Var
	min,max,i,j,k,m,n,pos			:Longint;
	std								:Longint;
	b,e								:Array[0..maxn]of Longint;
	next							:Array[0..maxn,0..1]of Longint;
	f								:Array[0..maxn,0..1]of Longint;
	tree							:Array[0..maxn*20]of rec;

Procedure Build_Tree(code,l,r:Longint);
var mid:Longint;
begin
	Tree[code].l:=l;Tree[code].r:=r;
	Tree[code].pos:=0;
	if l+1>=r then exit;
	mid:=(l+r)>>1;
	Build_Tree(code*2,l,mid);
	Build_Tree(code*2+1,mid,r);
end;

Procedure Insert_Tree(code,l,r:Longint);
var mid:Longint;
begin
	if (Tree[code].l=l)and(Tree[code].r=r)then 
		begin
			Tree[code].pos:=i;
			exit;
		end;
	if Tree[code].pos>-1 then 	
		begin
			Tree[code*2].pos:=Tree[code].pos;
			Tree[code*2+1].pos:=Tree[code].pos;
			Tree[code].pos:=-1;
		end;
	mid:=(tree[code].l+tree[code].r)>>1;
	if mid>=r then Insert_Tree(code*2,l,r) else
		if mid<=l then Insert_Tree(code*2+1,l,r) else
			begin
				Insert_Tree(code*2,l,mid);
				Insert_Tree(code*2+1,mid,r);
			end;
end;

Function Get(code,p:Longint):Longint;
var mid:Longint;
begin
	if Tree[code].pos<>-1 then exit(Tree[code].pos);
	if Tree[code].l+1=Tree[code].r then exit(Tree[code].pos);
	mid:=(Tree[code].l+Tree[code].r)>>1;
	if mid>=p then exit(Get(code*2,p))else exit(Get(code*2+1,p));
end;

BEGIN
	readln(n,pos);
	min:=maxlongint;max:=-maxlongint;
	for i:=n downto 1 do
		begin
			readln(b[i],e[i]);
			if b[i]<min then min:=b[i];
			if e[i]>max then max:=e[i];
		end;
	dec(pos,min-1);
	for i:=1 to n do
		begin
			dec(b[i],min-1);
			dec(e[i],min-1);
		end;
	Build_Tree(1,0,max-min+1);std:=-min+1;
	for i:=n downto 1 do
		begin
			next[i,0]:=Get(1,b[i]);
			next[i,1]:=Get(1,e[i]);
			Insert_Tree(1,b[i],e[i]);
		end;
	fillchar(f,sizeof(f),127);
	f[1,0]:=abs(pos-b[1]);f[1,1]:=abs(pos-e[1]);
	b[0]:=std;e[0]:=std;
	for i:=1 to n do
		if f[i,0]<(maxlongint>>1)then
			begin
				if f[i,0]+abs(b[i]-b[next[i,0]])<f[next[i,0],0] then f[next[i,0],0]:=f[i,0]+abs(b[i]-b[next[i,0]]);
				if f[i,0]+abs(b[i]-e[next[i,0]])<f[next[i,0],1] then f[next[i,0],1]:=f[i,0]+abs(b[i]-e[next[i,0]]);
				if f[i,1]+abs(e[i]-b[next[i,1]])<f[next[i,1],0] then f[next[i,1],0]:=f[i,1]+abs(e[i]-b[next[i,1]]);
				if f[i,1]+abs(e[i]-e[next[i,1]])<f[next[i,1],1] then f[next[i,1],1]:=f[i,1]+abs(e[i]-e[next[i,1]]);
			end;
	writeln(f[0,0]);
END.

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值