借助八数码问题,双向广搜,康托展开,逆序数奇偶性

来源:互联网 发布:破解局域网mac限制 编辑:程序博客网 时间:2024/06/13 20:19

1.首先判断是否有解

核心思想是根据一维状态的逆序数奇偶性来判断

将它表征为一维状态(0 1 2 3 4 5 6 7 8),它的逆序数为0,偶数。考虑数字的移动,左移or右移均不改变其一维状态,因此逆序数的奇偶性不变。上移or下移时,一维状态中某一位的数字往前或者往后跳了两格(+/-2),相应的,逆序数+/-2,依然不改变奇偶性。因此有结论:八数码问题有解 iff 初始状态与终止状态的逆序数奇偶性一致。

所以一个完美的八数码问题求解,必须先判断其解是否存在,再行搜索


2.双向广搜理论上可以减少一半的空间,时间。

1)将始 终状态都入队列并在相当的标记中为1,2(加以区分)

2)每次新的状态的标记都与上次的相同,并判断若有一个标记走到了另一个标记,结束

3)若要输出过程,标记变化的地方要单独输出

一个很好的模版 poj1915

#include <stdio.h>#include <stdlib.h>int vis[305][305], mat[305][305];int dx[] = {-2, -2, -1, 1, 2, 2, 1, -1};int dy[] = {-1, 1, 2, 2, 1, -1, -2, -2};int casenum, nNum, sx, sy, tx, ty, i;struct point{    int x, y;}cur, next, q[90005]={0};int IsInBound(int x, int y){    return (x>=0 && y>=0 && x<nNum && y<nNum);}/* IsInBound */int Solve(){    int rear = -1;    int front = -1;        cur.x = sx;    cur.y = sy;    vis[sx][sy] = 1; /* 从起始位置开始的探索标记为 1 */     q[++rear] = cur; /* 起始坐标入队 */         next.x = tx;    next.y = ty;    vis[tx][ty] = 2;  /* 从终点位置开始的探索标记为 2 */     q[++rear] = next; /* 终点坐标入队 */         while (front < rear)    {        cur = q[++front]; /* 队首节点坐标出队 */                for (i=0; i<8; ++i)        {            next.x = cur.x + dx[i];            next.y = cur.y + dy[i];                        if (!IsInBound(next.x, next.y))                continue;                            if (!vis[next.x][next.y])            {                vis[next.x][next.y] = vis[cur.x][cur.y];     /* 设为与当前探索路径相同的标记 */                mat[next.x][next.y] = mat[cur.x][cur.y] + 1; /* 记录步数 */                 q[++rear] = next; /* 当前合法坐标位置入队 */             }            else if (vis[cur.x][cur.y] != vis[next.x][next.y])            {   /* 说明从起点出发的探索与从终点出发的探索重合 */                 return mat[cur.x][cur.y]+mat[next.x][next.y]+1;//步数            }        }/* End of For */    }/* End of While */}/* Solve */int main(){    scanf("%d", &casenum);    while (casenum--)    {        memset(vis, 0, sizeof(vis));        memset(mat, 0, sizeof(mat));                scanf("%d", &nNum);        scanf("%d %d", &sx, &sy);        scanf("%d %d", &tx, &ty);                if (sx==tx && sy==ty)        {            printf("0\n");        }        else        {            printf("%d\n", Solve());        }        }/* End of While */        return 0;}
3.康托展开,hash判重

另一个完整的八数码结题答案

/*HDU 1043 Eight思路:反向搜索,从目标状态找回状态对应的路径用康托展开判重AC   G++  328ms  13924K*/#include<stdio.h>#include<string.h>#include<iostream>#include<queue>#include<string>using namespace std;const int MAXN=1000000;//最多是9!/2int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重//         0!1!2!3! 4! 5!  6!  7!   8!    9!bool vis[MAXN];//标记string path[MAXN];//记录路径int cantor(int s[])//康拖展开求该序列的hash值{    int sum=0;    for(int i=0;i<9;i++)    {        int num=0;        for(int j=i+1;j<9;j++)          if(s[j]<s[i])num++;        sum+=(num*fac[9-i-1]);    }    return sum+1;}struct Node{    int s[9];    int loc;//“0”的位置    int status;//康拖展开的hash值    string path;//路径};int move[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,rchar indexs[5]="durl";//和上面的要相反,因为是反向搜索int aim=46234;//123456780对应的康拖展开的hash值void bfs(){    memset(vis,false,sizeof(vis));    Node cur,next;    for(int i=0;i<8;i++)cur.s[i]=i+1;    cur.s[8]=0;    cur.loc=8;    cur.status=aim;    cur.path="";    queue<Node>q;    q.push(cur);    path[aim]="";    while(!q.empty())    {        cur=q.front();        q.pop();        int x=cur.loc/3;        int y=cur.loc%3;        for(int i=0;i<4;i++)        {            int tx=x+move[i][0];            int ty=y+move[i][1];            if(tx<0||tx>2||ty<0||ty>2)continue;            next=cur;            next.loc=tx*3+ty;            next.s[cur.loc]=next.s[next.loc];            next.s[next.loc]=0;            next.status=cantor(next.s);            if(!vis[next.status])            {                vis[next.status]=true;                next.path=indexs[i]+next.path;                q.push(next);                path[next.status]=next.path;            }        }    }}int main(){    char ch;    Node cur;    bfs();    while(cin>>ch)    {        if(ch=='x') {cur.s[0]=0;cur.loc=0;}        else cur.s[0]=ch-'0';        for(int i=1;i<9;i++)        {            cin>>ch;            if(ch=='x')            {                cur.s[i]=0;                cur.loc=i;            }            else cur.s[i]=ch-'0';        }        cur.status=cantor(cur.s);        if(vis[cur.status])        {            cout<<path[cur.status]<<endl;        }        else cout<<"unsolvable"<<endl;    }    return 0;}

4.A*启发搜索

0 0
原创粉丝点击