一个2*4的矩阵,有三种变换规则。
A | B | C |
---|---|---|
上下两行交换 | 将最右边的一列插入左边 | 中间四格顺时针旋转一次 |
给定一个目标矩阵,求最小翻转次数以及步骤。
这道题明显用深搜会超时,所以想到广搜。
8!=40320 可以过,现在要处理的就是判重。
方法 | HASH | map-int | map-string | 康托展开 |
---|---|---|---|---|
实现 | %一个很大的质数 | 直接用map中的int判重 | 用map中的string判重 | 一种另类的哈希 |
这里采用的是HASH方法。
本人亲测,40320会超时(因为不是一个质数而且过小),100003可以过30ms,1000003可以过15ms,0ms小编暂时没找到。
#include
#define p 100003//质数
#define hash(x) (x)%p//hash函数
#define r(i,a,b) for(int i=(a);i<=(b);i++)//循环
using namespace std;
const short rule[3][8]={{8,7,6,5,4,3,2,1},{4,1,2,3,6,7,8,5},{1,7,2,4,5,3,6,8}};//三种规则,其实这里从第0位开始应该要减一的,但为了方便,所以在后边有减一
char h[p][8],s[p+1],state[p+1][8]={{},{'1','2','3','4','5','6','7','8'}};//初始化state数组,h为hash数组,s为最终答案
int f[p+1],w[p+1],tot,head,tail;//f为father,w为对应的A or B or C
bool strstr(char a[],char b[])//判断两个字符串是否相同
{
r(i,0,7)
if(a[i]!=b[i]) return false;
return true;
}
void init()//输入
{
int x;
r(i,0,7)
{
scanf("%d",&x);
state[0][i]=x+48;//初始化
}
}
bool check(char s[])//判断这个字符串是否为空
{
r(i,0,7)
if(s[i]>='0'&&s[i]<='9') return true;//不空
return false;//空
}
int find(char s[])//查找s对应的位置
{
int t=0;
r(i,0,7)
t=(t<<3)+(t<<1)+s[i]-48;//转换
int orig=hash(t);//赋值给orig
while(check(h[orig])&&!strstr(h[orig],s))//不是空的并且不是目标对象
orig=hash(++orig);//继续往下走,hash是为了怕掉出去
return orig;//返回
}
void in(char s[])//将s存进hash表中
{
int t=0;
r(i,0,7)
t=(t<<3)+(t<<1)+s[i]-48;//转换
r(i,0,7)
h[hash(t)][i]=s[i];//存储
}
bool pd(char s[])//判断
{
if (strstr(h[find(s)],s)) return true;//若已经有了,返回true
else{in(s);return false;}//没有的话就把它存进去
}
void ppt(int x)//用来统计长度顺便保存路径
{
if(x==1) return;//到第一个了
s[++tot]=w[x]+65;//保存
ppt(f[x]);//继续递归
}
void bfs()//算法主体
{
tail=1;
r(i,0,7)
h[hash(12345678)][i]=state[1][i];//初始化
if(strstr(state[1],state[0])) return;//如果已经是12345678则无须再搜
do
{
head++;
r(i,0,2)
{
tail++;
f[tail]=head;
w[tail]=i;
r(j,0,7) state[tail][j]=state[head][rule[i][j]-1];//这里减一是因为C++是从第0位开始的
if(pd(state[tail])) {tail--;continue;}//如果已经找过了,就出队,并且直接返回
if(strstr(state[tail],state[0]))//如果已经找到了
{
ppt(tail);//统计
tail=0;//清空
return;//推出
}
}
}while(headint main()
{
init();//输入
bfs();//搜索
printf("%d\n",tot);
for(int i=tot;i>0;i--) putchar(s[i]);//输出
}