按紫书写……蜜汁tle,自测ac,为什么

#include<cstring>
using namespace std;
//八数码:隐式图 归结为图上的最短路
typedef int State[9];               //定义“状态”类型
const int maxstate=1000000;
State st[maxstate],goal={1,2,3,8,0,4,7,6,5};            //状态数组,所有状态都保存在这里
int dist[maxstate];             //距离数组
//如果需要打印方案,可以在这里加一个父亲编号数组int fa[maxstate]


const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
//bfs的方向数组
//并看不懂的编码与解码方法 
/*int vis[362880],fact[9];  //0-8的排列有9!=362880项 
void init_lookup_table(){   //解码与编码:紫书第十章 
    fact[0]=1;
    for(int i=1;i<9;i++) fact[i]=fact[i-1]*1;
}
int try_to_insert(int s){
    int code = 0;   //把st[s]映射到code
    for(int i=0;i<9;i++) 
    {
        int cnt=0;
        for(int j=i+1;j<9;j++) if(st[s][j]<st[s][i]) cnt++;
        code+=fact[8-i]*cnt;
    }
    if(vis[code]) return 0;
    return vis[code]=1;
}*/
//hash11方法
const int hashsize=1000003;
int head[hashsize],nxt[maxstate];
void init_lookup_table(){memset(head,0,sizeof(head));}
int hash1(State &s){//hash值相同的状态要组成链表 
        int v=0;
        for(int i=0;i<9;i++) v=v*10+s[i];//把九个数字组合成9位数
        return v%hashsize;//确保hash函数值是不超过hash表的大小的非负整数       
}
int try_to_insert(int s){//插入查找表 
        int h=hash1(st[s]);
        int u=head[h];      //从表头开始查找链表
        while(u){
            if(memcmp(st[u],st[s],sizeof(st[s])==0) )return 0;//找到了,插入失败
            u=nxt[u];                           //顺着链表继续找 
        } 
        nxt[s]=head[h];                     //插入 
        head[h]=s;
        return 1;   
    }

 
int bfs(){
    init_lookup_table();        //初始化查找表
    int front = 1,rear=2;//不用下标0,因为0被看作不存在
    while(front<rear){
        State &s=st[front];     //用“引用”简化代码
        if(memcmp(goal,s,sizeof(s))==0) return front;   //找到目标状态,成功返回
        int z;
        for(z=0;z<9;z++) if(!s[z]) break;   //找0的位置,即z的值
        int x=z/3,y=z%3;        //这步6,找0的坐标
        for(int d=0;d<4;d++)
        {
            int newx=x+dx[d];
            int newy=y+dy[d];
            int newz=newx*3+newy;//这操作……令人智熄……真的6 要我自己想的话怕是想不到这样表示0的坐标 
            if(newx>=0&&newx<3&&newy>=0&&newy<3){//如果移动合法 
                State& t=st[rear];  //rear的状态
                memcpy(&t,&s,sizeof(s));    //拓展新结点
                t[newz]=s[z];//移动0
                t[z]=s[newz];
                dist[rear]=dist[front]+1;   //更新新结点的距离值
                if(try_to_insert(rear)) rear++; //如果成功插入,修改队尾指针
                 
            }
         } 
         front++;   //拓展完毕后再修改队首指针 
    } 
    return 0;   //失败 
}//memcpy和memcmp 比循环比较和循环赋值要快 
int main(){
    for(int i=0;i<8;i++){
        char c;
        c=getchar();
        st[1][i]=c-48;
    }
    char c;
    scanf("%c",&c);
    st[1][8]=c-48;
    int ans=bfs();
    if(ans>0) printf("%d\n",dist[ans]);
    return 0;
    
}pp

0 条评论

目前还没有评论...

信息

ID
1360
难度
6
分类
搜索 | 搜索与剪枝 点击显示
标签
(无)
递交数
3875
已通过
928
通过率
24%
被复制
8
上传者