洛谷P2730 魔板

☞洛谷P2730 魔板☜

题目大意

一个2*4的矩阵,有三种变换规则。

A B C
上下两行交换 将最右边的一列插入左边 中间四格顺时针旋转一次

给定一个目标矩阵,求最小翻转次数以及步骤。

思路

这道题明显用深搜会超时,所以想到广搜。
8!=40320 可以过,现在要处理的就是判重。

方法 HASH map-int map-string 康托展开
实现 %一个很大的质数 直接用map中的int判重 用map中的string判重 一种另类的哈希

这里采用的是HASH方法。
本人亲测,40320会超时(因为不是一个质数而且过小),100003可以过30ms,1000003可以过15ms,0ms小编暂时没找到。

Code of Hash

#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]);//输出
}

你可能感兴趣的:(HASH)