篝火晚会(vijos1008)

算法:模拟
 
分析:一个挺难的模拟题了,主要是加上了对环的处理和操作。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.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值