典型的bfs, 第一个是自己写的没有做任何优化,需要8^8的空间保存状态
后来看了别人解题报告,学会了康托展开,全排列压缩,只需要8!空间
#include <iostream>
#include <string>
#include <queue>
#include <memory.h>
using namespace std;
struct my_status
{
int a[2][4];
string path;
my_status(){}
my_status(int a[2][4])
{
for (int i = 0; i < 2; i++)
for (int j = 0; j < 4; j++)
this->a[i][j] = a[i][j];
path = "";
}
my_status& operator=(const my_status& item)
{
for (int i = 0; i < 2; i++)
for (int j = 0; j < 4; j++)
a[i][j] = item.a[i][j];
path = item.path;
return *this;
}
bool operator== (const my_status& item)
{
for (int i = 0; i < 2; i++)
for (int j = 0; j < 4; j++)
if (a[i][j] != item.a[i][j])
return false;
return true;
}
};
bool isvisit[8][8][8][8][8][8][8][8];
int max_step;
int goal_status[2][4];
int inite_statue[2][4] = {{1,2,3,4}, {8,7,6,5}};
my_status do_operate(int, const my_status&);
void bfs();
int main()
{
while (cin >> max_step && max_step != -1)
{
memset(isvisit, false, sizeof(isvisit));
for (int i = 0; i < 2; i++)
for (int j = 0; j < 4; j++)
cin >> goal_status[i][j];
bfs();
}
return 0;
}
void bfs()
{
my_status p,next_status;
queue<my_status> Q;
char c;
Q.push(inite_statue);
while (!Q.empty())
{
p = Q.front();
Q.pop();
if (p.path.size() > max_step)
{
cout << "-1" << endl;
return;
}
if (p == goal_status)
{
cout << p.path.size() << " " << p.path << endl;
return;
}
for (int i = 0; i < 3; i++)
{
next_status = do_operate(i, p);
c = 'A'+i;
next_status.path = p.path + c;
if (!isvisit[next_status.a[0][0]-1][next_status.a[0][1]-1][next_status.a[0][2]-1][next_status.a[0][3]-1][next_status.a[1][0]-1][next_status.a[1][1]-1][next_status.a[1][2]-1][next_status.a[1][3]-1])
{
isvisit[next_status.a[0][0]-1][next_status.a[0][1]-1][next_status.a[0][2]-1][next_status.a[0][3]-1][next_status.a[1][0]-1][next_status.a[1][1]-1][next_status.a[1][2]-1][next_status.a[1][3]-1] = true;
Q.push(next_status);
}
}
}
}
my_status do_operate(int mode, const my_status& p)
{
my_status tmp;
switch (mode)
{
case 0:
for (int i = 0; i < 4; i++)
{
tmp.a[0][i] = p.a[1][i];
tmp.a[1][i] = p.a[0][i];
}
break;
case 1:
for (int i = 1; i < 4; i++)
{
tmp.a[0][i] = p.a[0][i-1];
tmp.a[1][i] = p.a[1][i-1];
}
tmp.a[0][0] = p.a[0][3];
tmp.a[1][0] = p.a[1][3];
break;
case 2:
tmp = p;
tmp.a[0][1] = p.a[1][1];
tmp.a[0][2] = p.a[0][1];
tmp.a[1][1] = p.a[1][2];
tmp.a[1][2] = p.a[0][2];
break;
}
return tmp;
}
康托展开
#include <iostream>
#include <string>
#include <queue>
#include <memory.h>
using namespace std;
struct my_status
{
int a;
string path;
};
int fact[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; //8!的阶乘表
bool isvisit[50000];
int max_step;
int goal_status;
int inite_statue = 12348765;
int do_operate(int, int);
//康托状态压缩
//把需要8^8的储存空间压缩成只需8!空间
//只有8!有效
int encode(int n)
{
int tmp[8];
int cnt, sum;
for (int i = 7; i >= 0; i--)
{
tmp[i] = n%10;
n /= 10;
}
for (int i = 0; i < 7; i++)
{
cnt = 0;
for (int j = i+1; j < 8; j++)
if (tmp[i] > tmp[j]) cnt++;
n += fact[8-i-1] * cnt;
}
return n;
}
void bfs();
int main()
{
int tmp[8];
while (cin >> max_step && max_step != -1)
{
memset(isvisit, false, sizeof(isvisit));
for (int i = 0; i < 8; i++)
cin >> tmp[i];
goal_status = tmp[0]*1e7 +tmp[1]*1e6 + tmp[2]*1e5 + tmp[3]*1e4 + tmp[4]*1e3 + tmp[5]*1e2 + tmp[6]*1e1 + tmp[7];
bfs();
}
return 0;
}
void bfs()
{
my_status p,next_status;
p.a = inite_statue;
p.path = "";
queue<my_status> Q;
char c;
Q.push(p);
while (!Q.empty())
{
p = Q.front();
Q.pop();
if (p.path.size() > max_step)
{
cout << "-1" << endl;
return;
}
if (p.a == goal_status)
{
cout << p.path.size() << " " << p.path << endl;
return;
}
for (int i = 0; i < 3; i++)
{
next_status.a = do_operate(i, p.a);
c = 'A'+i;
next_status.path = p.path + c;
if (!isvisit[encode(next_status.a)])
{
isvisit[encode(next_status.a)] = true;
Q.push(next_status);
}
}
}
}
int do_operate(int mode, int number)
{
int tmp = number;
switch (mode)
{
case 0: //操作A,上下行交换
tmp = number/1000%10*1e7 + number/100%10*1e6 + number/10%10*1e5 + number%10*1e4 + number/(10000000)%10*1e3 + number/1000000%10*1e2 + number/100000%10*10 + number/10000%10;
break;
case 1: //操作B,每行向后移动一位
tmp = number/10000%10*1e7 + number/10000000%10*1e6 + number/1000000%10*1e5 + number/100000%10*1e4 + number%10*1e3 + number/1000%10*1e2 + number/100%10*10 +number/10%10;
break;
case 2: //操作C,旋转
tmp = number/10000000%10*1e7 + number/100%10*1e6 + number/1000000%10*1e5 + number/10000%10*1e4 + number/1000%10*1e3 + number/10%10*1e2 + number/100000%10*10 + number%10;
break;
}
return tmp;
}