这题跟1150比,就是要多掌握一个康托展开,必须要排除一些已经访问过的情况而不是简单地添加,比如AA,BBBB,CCCC这些操作过后并没有改变原来的顺序,不排除的话,步数太多时,内存不够用。
康托展开就是一个全排列n!的数列与0~n!-1的一个双射,对于魔板中的任意一种状态都可以映射为一个自然数,并且是一一对应的。用于记录该状态是否被访问过。
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
int fact[8] = {0,1,2,6,24,120,720,5040};
bool isVisited[40320];
struct mb
{
int num;
string op;
mb()
{
num = 0;
}
bool operator==(mb &b)
{
return num == b.num;
}
};
int code(mb ori)
{
int tmp[8];
int code = 0;
for(int i = 7; i >= 0; i--)
{
tmp[i] = ori.num%10;
ori.num/=10;
}
for(int i = 0; i < 8; i++)
{
int count = 0;
for(int j = i + 1; j < 8; j++)
{
if(tmp[i]>tmp[j])
{
count++;
}
}
code += count * fact[8 - i - 1];
}
return code;
}
mb A(mb ori)
{
mb tmp;
tmp.num = ori.num%10000*10000+ori.num/10000;
tmp.op = ori.op + "A";
return tmp;
}
mb B(mb ori)
{
mb tmp;
tmp.num += ori.num%1000/10;
tmp.num += ori.num%10000/1000*100;
tmp.num += ori.num%10*1000;
tmp.num += ori.num%1000000/100000*10000;
tmp.num += ori.num/1000000*100000;
tmp.num += ori.num%100000/10000*10000000;
tmp.op = ori.op + "B";
return tmp;
}
mb C(mb ori)
{
mb tmp;
tmp.num += ori.num%10;
tmp.num += ori.num%1000000/100000*10;
tmp.num += ori.num%100/10*100;
tmp.num += ori.num%100000/1000*1000;
tmp.num += ori.num%10000000/1000000*100000;
tmp.num += ori.num%1000/100*1000000;
tmp.num += ori.num/10000000*10000000;
tmp.op = ori.op + "C";
return tmp;
}
void find(queue<mb> q,int n,mb aim)
{
while(!q.empty())
{
mb tmp = q.front();
q.pop();
if(tmp == aim && tmp.op.size() <= n)
{
cout << tmp.op.size() << " ";
cout << tmp.op;
cout << endl;
return;
}
else
{
mb Amb = A(tmp);
mb Bmb = B(tmp);
mb Cmb = C(tmp);
int ca = code(Amb);
int cb = code(Bmb);
int cc = code(Cmb);
if(!isVisited[code(Amb)])
{
q.push(Amb);
isVisited[ca] = true;
}
if(!isVisited[code(Bmb)])
{
q.push(Bmb);
isVisited[cb] = true;
}
if(!isVisited[code(Cmb)])
{
q.push(Cmb);
isVisited[cc] = true;
}
}
if(tmp.op.size() > n)
{
cout << -1 << endl;
return;
}
}
}
int main()
{
int n;
while(cin >> n && n != -1)
{
int tmp;
mb aim,one;
queue<mb> q;
memset(isVisited,false,40320);
//要改输入
for(int i = 0; i < 8; i++)
{
int tmp;
cin >> tmp;
aim.num = aim.num*10+tmp;
}
one.num = 12348765;
q.push(one);
find(q,n,aim);
}
}