HDU 3567 Eight II (搜索)

题意:给出两个状态的八数码,问输出第一个状态转移到第二个状态的满足以下条件的方案
1.步骤最少
2.字典序最小

如果直接进行转移,有几个很明显的问题,一时间不足,二如果双向BFS字典序不好处理,但是由于这道题的特殊性,我们只需要从一个状态转移到另一个状态,假设第一个输入为初状态,可以归纳为九类:012345678,102345678,120345678,123045678,123405678,123450678,123456078,123456708,123456780,分别作为初状态,第二个输入无非就是根据这些状态进行映射转移,由康托展开可以知道最多为3600000个状态,直接预处理出这九个状态的方案解决问题

#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");

using namespace std;

#define INF 0x3f3f3f3f
#define maxn 3600000

char d[]={"dlru"};
int dir[][5]={{1,0},{0,-1},{0,1},{-1,0}};

struct node
{
    int step;
    int index;
    int cant;
    char g[11];
}t[maxn];

int fa[10][maxn];
int ans[10][maxn];
int vis[10][maxn];

int fac[]= {1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800}; ///0~8
int cantor(char ss[])
{
    int s[10];
    for(int i=0; i<9; i++)
        s[i]=ss[i]-'0';
    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;
}

bool judge(int x,int y)
{
    return x>=0&&x<3&&y>=0&&y<3;
}

int que[maxn];
void bfs(int k,char s[])
{
    int l=0,r=-1;
    int cant=cantor(s);
    que[++r]=cant;
    memcpy(t[cant].g,s,sizeof t[cant].g);
    t[cant].index=k;
    fa[k][cant]=-1;
    t[cant].cant=cant;
    vis[k][cant]=1;
    t[cant].step=1;
    while(l<=r)
    {
        int f=que[l++];
        int x=t[f].index/3;
        int y=t[f].index-3*x;
        for(int i=0;i<4;i++)
        {
            int _x=x+dir[i][0];
            int _y=y+dir[i][1];
            if(judge(_x,_y))
            {
                node temp=t[f];
                swap(temp.g[temp.index],temp.g[_x*3+_y]);
                temp.cant=cantor(temp.g);
                if(vis[k][temp.cant]) continue;
                vis[k][temp.cant]=temp.step+1;
                ans[k][temp.cant]=i;
                fa[k][temp.cant]=f;
                temp.index=_x*3+_y;
                temp.step++;
                t[temp.cant]=temp;
                que[++r]=temp.cant;
            }
        }
    }
}

void print(int k,int st,int ed)
{
    if(ed==st) return ;
    print(k,st,fa[k][ed]);
    printf("%c",d[ans[k][ed]]);
}

int main()
{
    char str[20];
    strcpy(str,"012345678");
    bfs(0,str);
    strcpy(str,"102345678");
    bfs(1,str);
    strcpy(str,"120345678");
    bfs(2,str);
    strcpy(str,"123045678");
    bfs(3,str);
    strcpy(str,"123405678");
    bfs(4,str);
    strcpy(str,"123450678");
    bfs(5,str);
    strcpy(str,"123456078");
    bfs(6,str);
    strcpy(str,"123456708");
    bfs(7,str);
    strcpy(str,"123456780");
    bfs(8,str);
    int T;
    int ca=1;
    scanf("%d",&T);
    while(T--)
    {
        char str1[20],str2[20];
        int num[20];
        memset(num,0,sizeof num);
        int px,cant1,py,cant2;
        scanf("%s%s",str1,str2);
        for(int i=0,j=1; i<9; i++)
        {
            if(str1[i]=='X') str1[i]='0',px=i;
            if(str1[i]!='0') num[str1[i]-'0']=j,str1[i]=j+'0',j++;
        }
        for(int i=0;i<9;i++)
        {
            if(str2[i]=='X') str2[i]='0';
            str2[i]=num[ str2[i]-'0' ]+'0';
        }
        cant1=cantor(str1);
        cant2=cantor(str2);
        printf("Case %d: %d\n",ca++,vis[px][cant2]-1);
        print(px,cant1,cant2);
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值