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);
        }
    }
  • 相关阅读:
    web服务器-Apache
    nginx优化
    nginx下载限速
    nginx-URL重写
    HDU 5358 First One 求和(序列求和,优化)
    HDU 5360 Hiking 登山 (优先队列,排序)
    HDU 5353 Average 糖果分配(模拟,图)
    UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。
    HDU 5348 MZL's endless loop 给边定向(欧拉回路,最大流)
    HDU 5344 MZL's xor (水题)
  • 原文地址:https://www.cnblogs.com/yinbiao/p/10060504.html
Copyright © 2011-2022 走看看