您的位置:首页 > 其它

pku3460 Booksort

2012-03-17 10:49 148 查看
给定一个序列,每次可取出一段任意长度的序列插到某个位置,问至少多少次操作能让序列变为1.2.3.4......n。如果步数超过4,输出“5 or more”

可以用双向BFS,但编程复杂度较高,用迭代加深就需要动一点脑筋想强剪枝。

题目的最终状态是1 2 3 4 5 6 7 8,则严格递增序列为1。所谓严格递增即是说1 2 3 4 5 6,这些,而2 5,2 4 6,这种只能称之为递增,

那么1 2 5 6 3 4 7 8的严格递增序列有4个,

而每次操作最多一次减少3个非严格递增序列,所以有这个剪枝:if 当前递增序列个数-3*(最大深度-当前深度)>=0 then exit

加入这个剪枝不一定能AC,序列的重构一定要写的好一点,如果用n^4的操作,绝对超时。

顺便说一下,代码里的chaneg(i,j,k)表示把当前状态中(i..j)这个序列移动到第k个元素后面。

View Code

program pku3460(input,output);
type
numbertype = array[0..16] of integer;
var
state   : numbertype;
n,sum   : integer;
depth   : integer;
flag       : boolean;
v,cases : integer;
function check(a: numbertype ):integer;
var
sum,i : integer;
begin
sum:=0;
for i:=1 to n-1 do
if a[i+1]<>a[i]+1 then
inc(sum);
exit(sum+1);
end; { check }
procedure init;
var
i : integer;
begin
readln(n);
for i:=1 to n do
read(state[i]);
end; { init }
procedure change(x,y,z :longint );
var
i,now : longint;
tmp     : numbertype;
begin
fillchar(tmp,sizeof(tmp),0);
for i:=1 to x-1 do
tmp[i]:=state[i];
now:=x-1;
for i:=y+1 to z do
begin
inc(now);
tmp[now]:=state[i];
end;
for i:=x to y do
begin
inc(now);
tmp[now]:=state[i];
end;
for i:=z+1 to n do
tmp[i]:=state[i];
state:=tmp;
end; { change }
procedure dfs(now: integer );
var
i,j,k : integer;
tmp     : numbertype;
begin
if now>depth then
exit;
for i:=1 to n do
if state[i]>state[i+1] then
break;
if i=n then
flag:=true;
sum:=check(state);
if (sum-3*(depth-now+1)>=0) then
exit;
if flag then
exit;
tmp:=state;
for i:=1 to n-1 do
for j:=i to n-1 do
for k:=j+1 to n do
begin
change(i,j,k);
dfs(now+1);
state:=tmp;
if flag then
exit;
end;
end; { dfs }
procedure main;
begin
for depth:=0 to 4 do
begin
flag:=false;
dfs(0);
if flag then
break;
end;
if flag then
writeln(depth)
else
writeln('5 or more');
end; { main }
begin
readln(cases);
for v:=1 to cases do
begin
init;
main;
end;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: