幻方变换(puzzle)

版权声明:《本文为博主原创文章,转载请注明出处。 》 https://blog.csdn.net/zbq_tt5/article/details/88561618

题目描述:

  如果一个 3 × 3 的矩阵中,整数 1-9 中的每个都恰好出现一次,我们称这个矩阵为一个幻 方。 

   我们可以对一个幻方进行一些操作。具体来说,我们可以 

  • 选择幻方的一行,整体向右移动一格,并将最右侧的数字移到最左边;或者  

  • 选择幻方的一列,整体向下移动一格,并将最下侧的数字移到最上面。  

  例如,下面两个操作分别是一种合法的行操作和列操作:  

  显然,一个合法的幻方经过一次操作后一定还是合法的幻方。 

  给定幻方的初始状态,请问,最少要经过多少次变换,才能变成最终状态? 

输入描述:

第一行一个整数 T (1 ≤ T ≤ 200000),表示测试用例的数量。

接下来有 T 组测试用例,每组测试用例前有一个空行。每组样例的前 3 行为幻方的初始状态,后 3 行为幻方的最终状态。每行的数字之间没有空格。

保证初始状态和最终状态都是合法的幻方。

输出描述:

对于每组测试用例在一行内输出一个整数,表示答案。如果不可能从起始状态转变为最终状态,输出 impossible。

样例输入:

4

123
456
789
231
456
789

457
213
689
257
361
489

927
641
358
297
651
384

123
456
789
123
456
789

样例输出:

2
3
impossible
0

这道题在比赛的时候时间限制是10s,显然通过暴力的方法来做。

这里T的范围是小于等于200000,然后幻方变换的时候如果考虑使用bfs,那么时间复杂度就会十分大,那么解决本题就需要针对这个问题进行优化,那么就下来的问题就是考虑怎么优化。

既然T很大,那么是否可以使用同一个模板答案,然后只需要输出相应位置的数就行了呢?(如果可行的话,时间复杂度就直接下降了不少~~~)

而如果说要实现这个假设,就需要我们输入的所有的数据在开始的时候数据是相同,虽然题目中的数据不同,但题是死的,人是活的,可以将题中的起始数据转化成同一个数据,貌似行得通,那就试一下吧!

        for(int i=0;i<9;++i)
        {
            mmp[beginn[i]-'0']=i+1;
        }
        for(int i=0;i<9;++i)
        {
            endd[i]=mmp[endd[i]-'0']+'0';
        }
        for(int i=0;i<9;++i)
            beginn[i]=i+'1';

这里解决了以后,后面就简单了很多。

1、BFS

对于本题的搜索是以123456789为起始点进行的搜索,每次进行的操作是题目中给出的条件

手动进行行或者列整体的移动。

这里用到了count函数:其功能类似于find。这个函数使用一对迭代器和一个值做参数,返回这个值出现次数的统计结果。 
编写程序读取一系列int型数据,并将它们存储到vector对象中,然后统计某个指定的值出现了多少次。 

2、输出

考虑一个问题,什么时候输出impossible,什么时候输出次数。

在结果出现impossible的时候,也就是意味着现在出现的这个数是我们bfs所没有找到的,如果说找到了这个数,那么这个数用count计算得到的结果一定是大于0的。

AC代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<string>
using namespace std;
map<string,int>mp;
map<int,int >mmp;
struct xiao
{
    int step;
    string a;
} mapp[370000];
queue<xiao>q;

char beginn[10],endd[10];//用来存储起始图形数据和结束时候的图形数据
int T;
void bfs(xiao gin)
{
    xiao noww,er,nextt;
    q.push(gin);
    while(!q.empty())
    {
        er=q.front();
        q.pop();
        noww=er;
        for(int i=1; i<=6; ++i)
        {
            xiao now=noww;
            if(i==1)
                swap(now.a[0],now.a[1]),swap(now.a[0],now.a[2]);
            if(i==2)
                swap(now.a[3],now.a[4]),swap(now.a[3],now.a[5]);
            if(i==3)
                swap(now.a[6],now.a[7]),swap(now.a[6],now.a[8]);
            if(i==4)
                swap(now.a[0],now.a[3]),swap(now.a[0],now.a[6]);
            if(i==5)
                swap(now.a[1],now.a[4]),swap(now.a[1],now.a[7]);
            if(i==6)
                swap(now.a[2],now.a[5]),swap(now.a[2],now.a[8]);
            nextt.a=now.a;
            nextt.step=now.step+1;
            if(mp.count(nextt.a)>0)
                continue;
            else
            {
                mp[nextt.a]=nextt.step;
                q.push(nextt);
            }
        }
    }
}

int main()
{
    mp["123456789"]=0;
    xiao gin;
    gin.a="123456789";
    gin.step=0;
    bfs(gin);
    scanf("%d",&T);
    while(T--)
    {
        int cnt=0;
        char nnn[10];
        for(int i=0; i<3; ++i)
        {
            scanf("%s",&nnn);
            for(int j=0; j<3; ++j)
            {
                beginn[cnt++]=nnn[j];
            }

        }
        beginn[cnt]='\0';
        cnt=0;
        for(int i=0; i<3; ++i)
        {
            scanf("%s",nnn);
            for(int j=0; j<3; ++j)
            {
                endd[cnt++]=nnn[j];
            }
        }
        endd[cnt]='\0';
        for(int i=0;i<9;++i)
        {
            mmp[beginn[i]-'0']=i+1;
        }
        for(int i=0;i<9;++i)
        {
            endd[i]=mmp[endd[i]-'0']+'0';
        }
        for(int i=0;i<9;++i)
            beginn[i]=i+'1';
        if(mp.count(endd)<=0||mp.count(beginn)<=0)
        {
            cout<<"impossible"<<endl;
        }
        else
        {
              cout<<mp[endd]<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zbq_tt5/article/details/88561618