题目
Description
给定1到N的一个排列,再给定一些允许的交换方法,要求用最少的交换次数把该排列变为1,2,3,,,N。
Input
第一行包含两个整数N(1<=N<=12)和M(1<=M<=N*(N-1)/2),表示序列的长度以及允许的交换方案。
第二行输入1到N个初始排列情况。
接下来M行,每行两个整数A和B描述一个允许的交换方案,表示允许把当前排列中的第A个数和第B个数进行交换,保证A和B不相同。
输入保证一定存在解。
Output
输出一个整数表示最少需要的交换次数。
Sample Input
输入1:
2 1
2 1
1 2
输入2:
3 2
2 1 3
1 3
2 3
输入3:
5 5
1 2 3 4 5
1 5
2 5
1 4
1 1
3 5
Sample Output
输出1:
1
输出2:
3
输出3:
0
分析
观察数据范围,发现这里的N很小,也许可以用暴力来处理。
但是,如果用暴力的话,会出现很多重复状态,而且效率不高。
开始的起始状态我们是知道的,最终转移到的状态我们也是知道的,而且每种操作的改变对于正着做和反着做都是相同的。
- 所以这题应该用双向广搜
不过,我们如何记录它的状态?
开应该12维的布尔数组是不太科学的,
因为N很小只用12,而且 1213=106993205379072 这个数是可以用long long存的下的。
那么我们就将每一个序列看成应该12进制的数,再将它转换成为应该10进制数。
这样,我们就可以将每一个序列变成一个数。
然而,这里可能出现的状态不是很多,我们可以用hash表来储存和判重。
Code(c++)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <stdlib.h>
#include <math.h>
#define ll long long
#define mo 1000007
using namespace std;
ll ha[mo];
bool bz[mo];
int g[mo];
ll data[3*mo],da1[3*mo],z[15],s;
int a[15],t[15],f[15],cz[150][2];
int n,m,l,now;
int hash(ll x)
{
int k=x%mo;
while((ha[k])&&(ha[k]!=x))k=(k+1)%mo;
return k;
}
ll zz()
{
ll sum=0;
for(int i=1;i<=n;i++)
sum+=t[i]*z[n-i];
return sum;
}
void aa(ll x)
{
for(int i=1;i<=n;i++)
{
f[i]=x/z[n-i];
x=x%z[n-i];
}
}
int main()
{
z[0]=1;
for(int i=1;i<=13;i++)
z[i]=z[i-1]*12;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
t[i]=i-1;
a[i]--;
}
for(int i=1;i<=m;i++)
scanf("%d%d",&cz[i][0],&cz[i][1]);
da1[1]=zz();
l=hash(da1[1]);
ha[l]=da1[1];
bz[l]=1;
memcpy(t,a,sizeof(t));
data[1]=zz();
l=hash(data[1]);
ha[l]=data[1];
if(da1[1]==data[1])
{
printf("0\n");
return 0;
}
int i=0,j=1,p=0,q=1;
while((i<j)&&(p<q))
{
i++;
aa(data[i]);
now=g[hash(data[i])];
for(int k=1;k<=m;k++)
{
memcpy(t,f,sizeof(t));
l=t[cz[k][0]];
t[cz[k][0]]=t[cz[k][1]];
t[cz[k][1]]=l;
s=zz();
l=hash(s);
if(ha[l]==s)
{
if(bz[l])
{
printf("%d\n",g[l]+now+1);
return 0;
}
}
else
{
j++;
data[j]=s;
ha[l]=s;
bz[l]=0;
g[l]=now+1;
}
}
p++;
aa(da1[p]);
now=g[hash(da1[p])];
for(int k=1;k<=m;k++)
{
memcpy(t,f,sizeof(t));
l=t[cz[k][0]];
t[cz[k][0]]=t[cz[k][1]];
t[cz[k][1]]=l;
s=zz();
l=hash(s);
if(ha[l]==s)
{
if(!bz[l])
{
printf("%d\n",g[l]+now+1);
return 0;
}
}
else
{
q++;
da1[q]=s;
ha[l]=s;
bz[l]=1;
g[l]=now+1;
}
}
}
}