zoukankan      html  css  js  c++  java
  • 蓝桥杯 历届试题 九宫重排 (bfs+康托展开去重优化)

    Description

    如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

    我们把第一个图的局面记为:12345678.
    把第二个图的局面记为:123.46758
    显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
    本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。

    Input

    输入第一行包含九宫的初态,第二行包含九宫的终态。

    Output

    输出最少的步数,如果不存在方案,则输出-1。

    Sample Input

    样例输入1
    12345678.
    123.46758
    
    样例输入2
    13524678.
    46758123.

    Sample Output

    样例输出1
    3
    
    样例输出2
    22

    Source

    蓝桥杯
     
    分析:暴力bfs会超时
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define INF 99999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};//i的阶乘
    
    LL getval()
    {
        LL ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    int kt(int a[],int n)//康托展开
    {
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int c=0;
            for(int j=i+1;j<=n;j++)
            {
                if(a[j]<a[i])
                    c++;
            }
            ans+=(c*fac[n-i]);
        }
        return ans+1;
    }
    
    char str1[15],str2[15];
    int a[4][4],b[4][4];
    int sx,sy;
    int t[10];
    int h;
    int w;
    bool vis[100000000];
    
    struct node
    {
        int x,y,step;//x,y代表空格位置
        int c[4][4];//九宫格数组
        node(int xx,int yy,int ss,int cc[][4])//初始化
        {
            x=xx;
            y=yy;
            step=ss;
            for(int i=1; i<=3; i++)
                for(int j=1; j<=3; j++)
                    c[i][j]=cc[i][j];
        }
        int getkt()//得到结点数组的康托展开值
        {
            h=1;
            for(int i=1;i<=3;i++)
            {
                for(int j=1;j<=3;j++)
                {
                    t[h++]=c[i][j];
                }
            }
            return kt(t,9);
        }
    };
    
    void init()//初始化
    {
        int cnt=0;
        for(int i=1; i<=3; i++)//得到原始九宫格
        {
            for(int j=1; j<=3; j++)
            {
                if(str1[cnt]=='.')
                    a[i][j]=9,sx=i,sy=j;
                else
                    a[i][j]=str1[cnt]-'0';
                cnt++;
            }
        }
        cnt=0;
        for(int i=1; i<=3; i++)//得到目标九宫格
        {
            for(int j=1; j<=3; j++)
            {
                if(str2[cnt]=='.')
                    b[i][j]=9;
                else
                    b[i][j]=str2[cnt]-'0';
                cnt++;
            }
        }
        me(vis,false);//九宫格状态数组
        h=1;
        for(int i=1;i<=3;i++)//得到目标九宫格的康托展开值
        {
            for(int j=1;j<=3;j++)
            {
                t[h++]=b[i][j];
            }
        }
        w=kt(t,9);
    }
    int check(int x,int y)//边界约束
    {
        if(x<=3&&x>=1&&y<=3&&y>=1)
            return 1;
        return 0;
    }
    int bfs(int x,int y,int a[][4])
    {
        queue<node> q;
    
        q.push(node(x,y,0,a));
        vis[node(x,y,0,a).getkt()]=1;
    
        while(!q.empty())
        {
            int x=q.front().x;
            int y=q.front().y;
            int step=q.front().step;
            int c[4][4];
            for(int i=1; i<=3; i++)
                for(int j=1; j<=3; j++)
                    c[i][j]=q.front().c[i][j];
            q.pop();
    
            for(int i=0; i<4; i++)
            {
                int xx=x+dir[i][0];
                int yy=y+dir[i][1];
                int ss=step+1;
    
                int cc[4][4];
                if(check(xx,yy)==0)//越界
                    continue;
    
                for(int i=1; i<=3; i++)
                    for(int j=1; j<=3; j++)
                        cc[i][j]=c[i][j];
                cc[x][y]=cc[xx][yy];//移动
                cc[xx][yy]=9;
    
                if(vis[node(xx,yy,ss,cc).getkt()]==0)//判断该状态的九宫格有没有搜索过
                {
                    if(node(xx,yy,ss,cc).getkt()==w)//搜索到了目标
                    {
                        return ss;//返回步数
                    }
                    int temp=node(xx,yy,ss,cc).getkt();
    
                    vis[temp]=1;//标记该状态的九宫格已经搜索过
                    q.push(node(xx,yy,ss,cc));
                }
    
            }
        }
        return -1;
    }
    int main()
    {
        while(~scanf("%s",str1))
        {
            scanf("%s",str2);
            init();
    
            int ans=bfs(sx,sy,a);
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    程序员:不要自称为码农
    SpringBoot对静态资源配置
    LeetCode 572. Subtree of Another Tree(子树)
    LeetCode 437. Path Sum III(统计路径和等于sum的路径数量)
    LeetCode 112. Path Sum(判断路径和是否等于一个数)
    LeetCode 617. Merge Two Binary Trees(归并两棵二叉树)
    LeetCode 226. Invert Binary Tree(翻转二叉树)
    Failure to transfer org.apache.maven.plugins:maven-resources-plugin:pom:2.6 的解决办法
    linux-查询某软件的安装的目录
    WebService概念解释
  • 原文地址:https://www.cnblogs.com/yinbiao/p/10060504.html
Copyright © 2011-2022 走看看