poj 1077 zoj 1217 hdu 1043 八数码

poj 1077 zoj 1217 hdu 1043 八数码
题意:以sample为例

将  2 3 4             1 2 3

     1 5  x   —>    4 5 6

     7 6 8             7 8  x

x可以与上下左右交换,问最少的交换次数到达

上例的答案是:                     ullddrurdllurdruldr  

不过我程序运行的答案是:ullddrurdllurrdlurd
虽然结果不同,但是答案也是正确的,因为只要输出一个路径


下面说一下我的做法:

     我将3*3的矩阵压缩成一个数,x用0表示,状态总共有9!=362880种,我用一个数组记录,查找时用二分查找,(刚刚华爷(搜索神牛)告诉我只要hash mod1000007

刚刚好所有的数字都不会有重合的,这就是八数码一个神奇的地方,大家可以去试试)

   用bfs从123456780 扩展下去->123450786和123456708,直到队列空为止,记得要记录路径。

 

1077Accepted14116K391MSG++3147B

 

 Accepted 1217C++22016068

 

Accepted1043125MS14360K3331 BC++

 

看来hdu的服务器是最快的

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 1000000
const int n = 9;
int memory[N],top;
int a[n],b[n],p[n];
int maze[n+1][n+1];
void init()
{
    top=0;
    p[0] = 1;
    for(int i=1;i<n;i++) p[i] = p[i-1] * 10;
    b[n-1] = 1;
    for(int i=n-2;i>=0;i--) b[i] = b[i+1] *10;
    for(int i=0;i<n;i++) a[i] = i;
    do
    {
        int sum=0;
        for(int i=0;i<n;i++) sum += a[i]*b[i];
        memory[top++]  = sum;
    }while(next_permutation(a,a+n));
    memset(maze,0,sizeof(maze));
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
            maze[i][j]=1;
}
struct node
{
    int to,turn;
}path[N];
int mark[N];
struct info
{
    int x,index,pos;
};
int dx[]={-1,0,1,0};
int dy[]={0,1,0,-1};
int ad[]={-3,1,3,-1};
int pu[]={3,-1,-3,1};
int turnx[] = {1,1,1,2,2,2,3,3,3};
int turny[] = {1,2,3,1,2,3,1,2,3};
int turn(int k,int index,int x)
{
    int ret;
    int x1,x2;
    x1 = x/b[index]%10;
    x2 = x/b[index+ad[k]]%10;
    ret = x - x1*b[index] - x2*b[index+ad[k]] + x1*b[index+ad[k]] + x2*b[index];
    return ret;
}
int ll;
void bfs()
{
    memset(path,-1,sizeof(path));
    memset(mark,0,sizeof(mark));
    queue<struct info> q;
    struct info tmp1,tmp2; 
    int l,r,sum = 0;
    for(int i=1;i<n;i++) sum += i*b[i-1];
    tmp1.x = sum; tmp1.index = 8;
    ll=l = lower_bound(memory,memory+top,sum) - memory;
    tmp1.pos=l;
    mark[l] = 1;
    q.push(tmp1);
    while(!q.empty())
    {
        tmp1 = q.front();
        q.pop();
        int xx = turnx[tmp1.index], yy = turny[tmp1.index];
        for(int k=0;k<4;k++)
        {
            int x = xx +dx[k],y = yy + dy[k];
            if(maze[x][y])
            {
                tmp2.x = turn(k,tmp1.index ,tmp1.x);
                l = lower_bound(memory,memory+top,tmp2.x)-memory;
                if(mark[l]==0)
                {
                    tmp2.index = tmp1.index + ad[k];
                    tmp2.pos = l;
                    path[l].turn = k;
                    path[l].to = tmp1.pos;
                    q.push(tmp2);
                    mark[l] = 1;
                }
            }
        }
    }
}
int main()
{
//    freopen("in","r",stdin);
    init();
    bfs();
    int sum=0,l;
    char ch;
    while(cin>>ch)
    {
        if(ch!='x') sum = (ch-'0')*b[0];
        else sum = 0;
        for(int i=1;i<n;i++)
        {
            cin>>ch;
            if(ch == 'x') continue;
            sum += (ch - '0') * b[i];
        }
        l = lower_bound(memory,memory+top,sum) - memory;
        if(mark[l]==0) printf("unsolvable");
        else
        {
            while(l!=ll)
            {
                if(path[l].turn==0) putchar('d');
                else if(path[l].turn==1) putchar('l');
                else if(path[l].turn==2) putchar('u');
                else putchar('r');
                l=path[l].to;
            }
        }
        printf("\n");
    }
    return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值