POJ 1077 Eight(BFS:输出路径)

POJ 1077 Eight(BFS:输出路径)

http://poj.org/problem?id=1077

题意:

        给你一个八数码3*3的网格,要你输出解的路径.

分析:

        首先状态设计肯定当前网格是9个格子对应的值以及距离。然后如果你用dist[10][10][10][10][10][10][10][10][10]来判断一个状态是否已经出现过的话,肯定空间要爆的。所以本题下面用的策略是:用hash表来判断一个状态是否重复出现,保存出现过得所有非重复状态。

        参考刘汝佳入门经典P132.

        首先对于每个网格状态,我们把它转化为一个9位的十进制数.然后用state[][9]二维数组来保存所有的我们已经发现的状态st,且用state[]来表示当前我们用的栈.

        对于每个节点的判重,我们需要用到hash表来映射判重.

        具体细节看代码。

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int max_state=1000003;  //错0,这里9!=362880,我看成了3W6,就写了100003了.导致存取越界
int dx[]={-1,1,0,0};//上,下,左,右
int dy[]={0,0,-1,1};
int goal[]={1,2,3,4,5,6,7,8,0};
struct Node
{
    int st[9];
    int d;//表示前一步的操作方向
    int pre;//前一个状态的下标
    Node(){}
}state[max_state];//state从1开始计数,因为0被看做不存在
struct HASHMAP
{
    int head[max_state];
    int next[max_state];
    void init(){memset(head,0,sizeof(head));}//初始化,0号状态代表不存在
    int hash(int *st)                        //这个st是一个st[9]
    {
        int v=0;
        for(int i=0;i<9;i++)
            v=v*10+st[i];
        return v%max_state;
    }
    bool try_insert(int st)                  //这个st是state的下标
    {
        int h=hash(state[st].st);
        int u=head[h];
        while(u)
        {
            if(memcmp(state[u].st,state[st].st,sizeof(state[u].st) )==0) return false;//状态已存在,插入失败
            u=next[u];
        }
        next[st]=head[h];
        head[h]=st;
        return true; //插入成功
    }
}hm;
int BFS()//返回目标状态的下标
{
    hm.init();
    int front=1,rear=2;//首状态已经读入state数组了
    while(front<rear)
    {
        Node node=state[front];
        int z,x,y;
        for(int i=0;i<9;i++) if(node.st[i]==0) {z=i;break;}//找到0的位置
        x=z/3 , y=z%3;                                     //x与y是0所在的行和列号
        for(int d=0;d<4;d++)
        {
            int nx=x+dx[d] ,ny=y+dy[d];
            if(nx>=0&&nx<3&&ny>=0&&ny<3)                    //错1,这里写成<=3了
            {
                int nz=nx*3+ny;//需要调换的位置
                state[rear] = node;
                state[rear].d=d;
                state[rear].st[z]=node.st[nz];
                state[rear].st[nz]=node.st[z];
                state[rear].pre=front;
                if(hm.try_insert(rear))
                {
                    rear++;
                    if(memcmp(goal,state[rear-1].st,sizeof(goal))==0) return rear-1; //错2,这里两个rear-1都写成了rear
                }
            }
        }
        front++;            //错3,这里忘了
    }
    return -1;
}
int main()
{
    char x;
    int i=0;
    while((x=getchar())!=EOF)
    {
        if(x=='x') state[1].st[i++]=0;
        else if(x>='1'&&x<='8') state[1].st[i++]=x-'0';
        if(i>=9) break;                                    //错4这里i忘了++
    }
    int ans=BFS();
    if(ans==-1) printf("unsolvable\n");
    stack<int> S;
    while(ans!=1)
    {
        S.push(state[ans].d);
        ans=state[ans].pre;
    }
    while(!S.empty())                 //错5,这里忘了!
    {
        int dir=S.top();S.pop();
        if(dir==0)putchar('u');
        else if(dir==1)putchar('d');
        else if(dir==2)putchar('l');
        else if(dir==3)putchar('r');
    }
}

AC代码2:G++

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<stack>
using namespace std;
const int max_state = 1000000+3000;

struct Node
{
    Node(){}
    char st[9];
    int pre;
    int dir;
}vc[1000000+3000];
int cnt=0;

int dr[]={-1,1,0,0};//上下左右
int dc[]={0,0,-1,1};

struct HASHMAP
{
    int head[max_state];
    int next[max_state];
    HASHMAP()
    {
        memset(head,-1,sizeof(head));
    }
    int hash(char *st)                        //这个st是一个st[9]
    {
        int v=0;
        for(int i=0;i<9;i++)
            v=v*10+st[i];
        return v%max_state;
    }
    bool try_insert(int st)                  //这个st是state的下标
    {
        int h=hash(vc[st].st);
        int u=head[h];
        while(u!=-1)
        {
            if(memcmp(vc[u].st,vc[st].st,sizeof(vc[u].st) )==0) return false;//状态已存在,插入失败
            u=next[u];
        }
        next[st]=head[h];
        head[h]=st;
        return true; //插入成功
    }
}hm;

bool check_end(const char* str)
{
    char tmp[]="12345678x";
    for(int i=0;i<9;i++)
        if(tmp[i]!=str[i])
        return false;
    return true;
}

int BFS(Node& root)
{
    if(check_end(root.st))
        return 0;

    vc[cnt++] = root;
    queue<int> Q;
    Q.push(0);
    hm.try_insert(0);

    while(!Q.empty())
    {
        int v =Q.front(); Q.pop();
        int x;
        for(x=0;x<9;x++)
            if(vc[v].st[x]=='x') break;
        int r = x/3, c=x%3;

        for(int dir=0;dir<4;dir++)
        {
            char st[9];
            for(int i=0;i<9;i++)
                st[i] = vc[v].st[i];
            int nr = r + dr[dir];
            int nc = c + dc[dir];

            if(nr<0||nr>=3 || nc<0 || nc>=3) continue;

            swap(st[x],st[nr*3+nc]);

            for(int i=0;i<9;i++)
                vc[cnt].st[i]=st[i];
            vc[cnt].dir = dir;
            vc[cnt].pre = v;
            if(hm.try_insert(cnt))
            {
                ++cnt;
                Q.push(cnt-1);
                if(check_end(vc[cnt-1].st))
                    return cnt-1;
            }
        }
    }
    return -1;
}

int main()
{
    char ch;
    Node root;
    for(int i=0;i<9;i++)
    {
        scanf(" %c",&ch);
        root.st[i]=ch;
    }
    root.pre = -1;
    root.dir = -1;

    int res = BFS(root);

    if(res == -1) printf("unsolvable\n");
    else
    {
        stack<int> S;
        while(res != 0)
        {
            S.push(vc[res].dir);
            res= vc[res].pre;
        }

        while(!S.empty())
        {
            int u = S.top(); S.pop();
            if(u==0) printf("u");
            else if(u==1) printf("d");
            else if(u==2) printf("l");
            else if(u==3) printf("r");
        }
        printf("\n");
    }

    return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值