description
给定1到N的一个排列,再给定一些允许的交换方法,要求用最少的交换次数把该排列变为1,2,3,,,N。
analysis
-
nnn比较小,考虑搜索,dfsdfsdfs不可能,bfsbfsbfs可以试试
-
注意一点,起始状态和终止状态都已经给出了,那么用双向bfs
-
由于搜索树从一棵变成两棵,双向复杂度是单向的开方级别,用哈希判重
-
把当前状态压成一个十进制下的十三进制数,不超过longlonglong longlonglong,所以我们把哈希也开longlonglong longlonglong即可
-
接下来就很简单了,从起始状态和终止状态开始扩展,一个状态出现两次直接输出退出
code
- 由于和谐的空间限制,我的哈希开的不大,虽说是正解但TTT了一个点
看情况适当打表
const
maxn=1000007;
type
arr=array[0..12]of longint;
var
que1,que2,hash1,hash2:array[0..maxn]of
record
s:int64;
sum:longint;
end;
x,y:array[0..100]of longint;
n,m,i,j,h1,t1,h2,t2:longint;
flag:boolean;
temp:int64;
a,b:arr;
procedure swap(var x,y:longint);
var
z:longint;
begin
z:=x;
x:=y;
y:=z;
end;
function turn(t:arr):int64;
var
tp:int64;
i:longint;
begin
turn:=0;
tp:=1;
for i:=12 downto 1 do
begin
if t[i]>0 then
turn:=turn+t[i]*tp;
tp:=tp*13;
end;
end;
procedure return(n:int64;var t:arr);
var
i:longint;
begin
fillchar(t,sizeof(t),0);
for i:=12 downto 1 do
begin
t[i]:=n mod 13;
n:=n div 13;
end;
end;
function find1(x:int64):boolean;
var
now:longint;
begin
now:=x mod maxn;
if hash1[now].s=0 then exit(true);
if hash1[now].s=x then exit(false);
now:=(now+1)mod maxn;
while (hash1[now].s<>0)and(hash1[now].s<>x)do
begin
inc(now);
if now=maxn then now:=0;
end;
if hash1[now].s=0 then exit(true);
if hash1[now].s=x then exit(false);
end;
procedure into1(x:int64;y:longint);
var
now:longint;
begin
now:=x mod maxn;
if hash1[now].s=0 then
begin
hash1[now].s:=x;
hash1[now].sum:=y;
exit;
end;
now:=(now+1)mod maxn;
while (hash1[now].s<>0)and(hash1[now].s<>x) do
begin
inc(now);
if now=maxn then now:=0;
end;
hash1[now].s:=x;
hash1[now].sum:=y;
end;
function find2(x:int64):boolean;
var
now:longint;
begin
now:=x mod maxn;
if hash2[now].s=0then exit(true);
if hash2[now].s=x then exit(false);
now:=(now+1)mod maxn;
while (hash2[now].s<>0)and(hash2[now].s<>x)do
begin
inc(now);
if now=maxn then now:=0;
end;
if hash2[now].s=0 then exit(true);
if hash2[now].s=x then exit(false);
end;
procedure into2(x:int64;y:longint);
var
now:longint;
begin
now:=x mod maxn;
if hash2[now].s=0 then
begin
hash2[now].s:=x;
hash2[now].sum:=y;
exit;
end;
now:=(now+1)mod maxn;
while (hash2[now].s<>0)and(hash2[now].s<>x) do
begin
inc(now);
if now=maxn then now:=0;
end;
hash2[now].s:=x;
hash2[now].sum:=y;
end;
function lookfor(x:int64):longint;
var
now:longint;
begin
now:=x mod maxn;
if hash1[now].s=x then exit(hash1[now].sum);
while true do
begin
inc(now);
if now=maxn then now:=0;
if hash1[now].s=x then exit(hash1[now].sum);
end;
end;
begin
readln(n,m);
flag:=true;
for i:=1 to n do
begin
read(a[i]);
if a[i]<>i then flag:=false;
b[i]:=i;
end;
if flag then
begin
writeln(0);
halt;
end;
for i:=1 to m do readln(x[i],y[i]);
h1:=0;
t1:=1;
h2:=0;
t2:=1;
que1[1].s:=turn(a);
que2[1].s:=turn(b);
repeat
inc(h1);
if h1=maxn then h1:=0;
for i:=1 to m do
begin
return(que1[h1].s,b);
swap(b[x[i]],b[y[i]]);
temp:=turn(b);
if find1(temp) then
begin
into1(temp,que1[h1].sum+1);
inc(t1);
if t1=maxn then t1:=0;
que1[t1].s:=temp;
que1[t1].sum:=que1[h1].sum+1;
end;
end;
inc(h2);
if h2=maxn then h2:=0;
if not find1(que2[h2].s)then
begin
writeln(que2[h2].sum+lookfor(que2[h2].s));
halt;
end;
for i:=1 to m do
begin
return(que2[h2].s,b);
swap(b[x[i]],b[y[i]]);
temp:=turn(b);
if find2(temp)then
begin
into2(temp,que2[h2].sum+1);
inc(t2);
if t2=maxn then t2:=0;
que2[t2].s:=temp;
que2[t2].sum:=que2[h2].sum+1;
end;
end;
until false;
end.

本文介绍如何使用双向BFS算法解决一个排列变换问题,即通过给定的交换操作将一个1到N的排列变换为有序排列1,2,3,...,N,并寻找最小的变换次数。文中详细解释了如何将排列状态压缩为数值形式,利用哈希表进行状态存储与判重,从而降低搜索复杂度。
261

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



