提升coding能力------搜索专题(3)-----poj 1077

pku 1077 Eight

题目地址:http://poj.org/problem?id=1077

题目大意:

经典的八数码问题,给你一个3*3,其中一个数位x的图,问是否能通过移动x,来使图形成为一个

123

456

78x

这样图形,可以的话,输出x 的移动路径,经典的BFS。

详细分析:

这边先点一下,以后详细填坑。

这边的话需要用到康托展开,康拓展开也可以看成一种hash函数,关键是得用一种映射方法,把你当前的搜索状态(我猜是一个图),映射为一个值,便于判断是否搜索过,可以用来减少判重时间的同时还可以避免不必要的搜索

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
typedef long long ll;
#define aim  1 //目标图形对应的cantor值
struct Node
{
    int Map[9];
    ll val; //康拓展开对应的值
    int x;

};
char s[100];
ll ans[9] ={1, 1, 2, 6, 24, 120, 720, 5040, 40320};
int dirc[4][2] = {{1,0},{-1,0},{0,-1},{0,1}};
char opt[4] = {'d', 'u', 'l', 'r'};
int vis[500005];
int pre[500005];
char path[500005];
ll Cantor(Node& t)
{
    ll ret = 0;
    for(int i = 0 ;i < 9; i++)
    {
        int cnt = 0;
        for(int j = i + 1 ; j < 9 ;j++ )
        {
            if(t.Map[j] < t.Map[i])
                cnt++;
        }

        ret += cnt* ans[ 8 - i ];
    }

    return ret + 1;
}
int BFS(Node& T) //找初始点到目标节点的最短路径
{
    queue<Node> q;

    Node temp , Front ;
    temp = T;
    vis[temp.val] = 1;
    q.push(temp);

    while(!q.empty())
    {
        Front = q.front();
        q.pop();

        if(Front.val == aim)
        {
              return 1;
        }

        for(int i = 0 ;i < 4; i++)
        {

            temp = Front;
            int pos_x = temp.x/3;
            int pos_y = temp.x%3;

            pos_x += dirc[i][0];
            pos_y += dirc[i][1];

            if( pos_x>=0 && pos_x <3 && pos_y >=0 && pos_y <3 )
            {
                swap( temp.Map[pos_x*3 + pos_y], temp.Map[temp.x]);

                ll can_val = Cantor(temp);

                if(!vis[can_val])
                {

                    temp.val = can_val;
                    temp.x = pos_x*3 + pos_y;
                    vis[can_val] = 1;
                    pre[temp.val] = Front.val;
                    path[temp.val] = opt[i];
                    q.push(temp);


                }

             }



         }


     }

     return 0;
}


void show_path(int i)
{
    if(i == 0)
        return ;

    show_path( pre[i] );

    if( pre[i] != 0 )
      cout <<  path[i];

}


int main()
{
   Node First;
   while(gets(s))
   {
       memset(vis,0,sizeof(vis));
       int index = 0;
       for(int i = 0 ;i < strlen(s); i++) //二维数组用一维存储
       {
           if(s[i] >='1' && s[i] <='8')
              First.Map[ index++ ] = s[i] -'0';
           else if(s[i] == 'x')
           {
              First.x = index;
              First.Map[index++ ] = 9;

           }
       }


      First.val = Cantor(First) ;
      pre[First.val] = 0;

       /*
       cout << First.val << endl;
       cout << First.x << endl;
       for(int i = 0 ;i < 9 ;i++)
          cout << First.Map[i] << endl;
          */


      if( BFS(First) )
      {

          show_path(1);
          cout << endl;
      }
      else
          cout << "unsolvable"<< endl;

       // cout << pre[1] << endl;

       //cout << "have done" << endl;



   }

   return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值