算法:模拟
分析:一个挺难的模拟题了,主要是加上了对环的处理和操作。NOIP2005原题。
这个题考察的是对环的理解程度,因为原序列是从1~n按序排好的,因此我们可以构造出一个目标序列,然后根据这个目标序列去推起始序列。
因为要求移动的次数最少,所以当前的数与位置能够相互对应上的我们就可以不去管它了,只关注那些没有对应上的,没有对应上的我们用数-它应该在的位置。
分析:一个挺难的模拟题了,主要是加上了对环的处理和操作。NOIP2005原题。
这个题考察的是对环的理解程度,因为原序列是从1~n按序排好的,因此我们可以构造出一个目标序列,然后根据这个目标序列去推起始序列。
因为要求移动的次数最少,所以当前的数与位置能够相互对应上的我们就可以不去管它了,只关注那些没有对应上的,没有对应上的我们用数-它应该在的位置。
问题就是求何时能使归位的元素数量最多。
program VJ1008;
const
maxn=50000;
var
n,ans:longint;
dream:array [0..maxn,1..2] of longint;
dec1,dec2,a:array [0..maxn] of longint;
procedure init;
var
i:longint;
begin
readln(n);
for i:=1 to n do readln(dream[i,1],dream[i,2]);
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;
procedure main;
var
i,t1,t2:longint;
begin
fillchar(dec1,sizeof(dec1),0);
fillchar(dec2,sizeof(dec2),0);
for i:=1 to n do
begin
{将数组正向和反向同时求移动多少次才能回到原位。}
t1:=a[i]-i;
t2:=a[n-i+1]-i;
if t1<0 then inc(dec1[n+t1]) else inc(dec1[t1]);
if t2<0 then inc(dec2[n+t2]) else inc(dec2[t2]);
end;
{移动相同次数回到原位的就可以认为是一开始就呆在了正确的位置上,因为它们都可以通过移动相同的次数回到原位,所以要找的就是使能呆在原位置上的数尽可能的多
* 这样的话就可以使不在原位置上的数最少。}
for i:=0 to n do ans:=max(ans,max(dec1[i],dec2[i]));
writeln(n-ans);
end;
procedure makeit;
var
i,j:longint;
begin
a[1]:=1;
j:=dream[1,2];
for i:=2 to n do
begin
if dream[j,2]=a[i-1] then{如果i-1是j右边想挨着的人就构造他的左边,否则构造它的右边。}
begin
a[i]:=j;
j:=dream[j,1];
end
else if dream[j,1]=a[i-1] then
begin
a[i]:=j;
j:=dream[j,2];
end
else
begin
writeln(-1);
close(input);
close(output);
halt;
end;
end;
{无法完成构造的情况:最终没有构成环或是之前就没有构成环。}
if j<>1 then
begin
writeln(-1);
close(input);
close(output);
halt;
end;
main;
end;
begin
assign(input,'VJ1008.in'); reset(input);
assign(output,'VJ1008.out'); rewrite(output);
init;
makeit;
close(input); close(output);
end.
本文介绍了一道复杂的模拟算法题目,重点在于理解序列中的环状结构,并通过构造目标序列来推导原始序列。文章提供了完整的Pascal代码实现,展示了如何通过计算元素移动次数来找到最优解。
1418

被折叠的 条评论
为什么被折叠?



