UVA 10085 The most distant state (hash隐式图搜索)

题意:给出初始图找出可达目标图,步数最多的一个,并输出路径。
这题很像八数码格。情况有9!种。
用康托展开来进行哈希(哈希值等于当前数是未出现数字中第几个,然后乘上(n-i)!)
比如 1 3 2 0 4
那么hash=1*4!+2*3!+1*2!+0*1!+0*0!;
然后进行bfs,用一个vis数组标记已经出现过的状态(hash值)
那么队列种最后留下来的肯定就是步数最多的了。
AC代码

#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
int hashh[10];
int vis[400000];
struct tree
{
    int hash;
    int x,y; 
  //0的位置,避免多次查找
    int map[3][3];
 
};
int prehash[400000],preforword[400000];
 //用来记录路径
int dir[4][2]={-1,0,0,-1,1,0,0,1};
char m[10]="ULDR";
int gethash(int a[])
  //hash函数
{
    int ha=0,t=0;
    int f[10]; 
    memset(f,0,sizeof(f)); 
    for(int i=0;i<9;i++)
    {
        t=0;
        for(int j=0;j<9;j++)
        if(j<a[i]&&!f[j])
        t++;
        f[a[i]]=1;
        ha+=t*hashh[8-i];
    }
    return ha;
}
int main()
{
    int T,cas=0;
    scanf("%d",&T);
    hashh[0]=1;
    for(int i=1;i<=8;i++)
    hashh[i]=hashh[i-1]*i;
    while(T--)
    {
        memset(prehash,0,sizeof(prehash));
        memset(preforword,0,sizeof(preforword));
        memset(vis,0,sizeof(vis));
        int a[10];
        tree p;
        for(int i=0;i<9;i++)
  
        {
            scanf("%d",&a[i]);
            if(a[i]==0)
            p.x=i/3,p.y=i%3;
        }
        p.hash=gethash(a);
        int jj=0,ii=0;
        for(int i=0;i<9;i++)
        {
            if(i%3==0&&i!=0)
            ii++,jj=0;
            p.map[ii][jj]=a[i];
            jj++;
        }
        queue<tree>q;
        q.push(p);
        vis[p.hash]=1;
        preforword[p.hash]=-1;
        int aim=p.hash;
        while(!q.empty())
        {
            p=q.front();
            q.pop();
            for(int i=0;i<4;i++)
            {
                tree pp=p;
                if(p.x+dir[i][0]<0||p.x+dir[i][0]>=3||p.y+dir[i][1]>=3||p.y+dir[i][1]<0)
                continue;
                pp.map[p.x][p.y]=pp.map[p.x+dir[i][0]][p.y+dir[i][1]];
                pp.map[p.x+dir[i][0]][p.y+dir[i][1]]=0;
                pp.x=p.x+dir[i][0];
                pp.y=p.y+dir[i][1];
                int aa[10],ttt=0;
                for(int ii=0;ii<3;ii++)
                {
                    for(int jj=0;jj<3;jj++)
                    aa[ttt++]=pp.map[ii][jj];
                }
                pp.hash=gethash(aa);
                if(!vis[pp.hash])
                {
                    preforword[pp.hash]=i;
                    prehash[pp.hash]=p.hash;
                    vis[pp.hash]=1;
                    q.push(pp);
                }
            }
        }
        printf("Puzzle #%d\n",++cas);
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<3;j++)
            {
                printf("%d",p.map[i][j]);
                if(j!=2)
                printf(" ");
            }
            printf("\n");
        }
        char anss[400000];
        int tp=0;
        while(preforword[p.hash]!=-1)
        {
            anss[tp++]=m[preforword[p.hash]];
            p.hash=prehash[p.hash];
        }
        for(int i=tp-1;i>=0;i--)
        printf("%c",anss[i]);
        printf("\n\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值