HDU 4531 吉哥系列故事——乾坤大挪移 (BFS)

吉哥系列故事——乾坤大挪移

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 184    Accepted Submission(s): 50

Problem Description   只有进入本次马拉松复赛,你才有机会知道一个秘密:吉哥的真名叫基哥,江湖人称“叽叽哥”。

  叽叽哥除了编程,还一直有个武侠梦,他最喜欢的人物是金庸小说《倚天屠龙记》中的张无忌,不仅有美人环绕,而且有一身的好武功,尤其是那神秘的乾坤大挪移,让他梦寐以求:

  

  
“乾坤大挪移乃在颠倒一刚一柔、一阴一阳的乾坤二气,随意而行,不用心而无不心用,所谓至我逍遥游,以纯阳之身,和纯阴之体,合练双修,不动身,只用意,意动身守……”

  

  但是,梦毕竟只是梦,平时在编程的空闲时间,叽叽哥也最多只能上网玩一下名为“乾坤大挪移”的游戏聊以自慰而已。

  这个“乾坤大挪移”游戏是在3*3的方格中进行。

  游戏的目标是通过移动,让相同颜色的块形成一个连通块(相邻是指两个块有边相邻,角相邻不算)。

  移动规则如下:选择一行(列),向左右(上下)移动一格,方格从一边划出,则从对应的另外一边划入,像履带一样。

  如选择第一行向右边移动,最右边的那格会移动到最左边。

  游戏中还有一些方格被固定住,这些方格没办法移动(如下图的第三行第二列)。

  下图是游戏的一个演示(即Case 1):

  假设现在告诉你初始状态,请问你最少需要几步才能达到目标?  

 

Input 第一行一个整数T代表接下去有T组数据;

每组数据由3*3的模块组成,每个模块表示的小正方形是由上下左右四个小三角形组成;

每个模块有5个字符,前四个字符分别表示组成正方形的上下左右四个小三角形的颜色,第五个字符表示该格子能否移动(0表示能移动,1表示不能移动).

[Technical Specification]

0<T<=100

代表颜色的字符一定是RGBO的其中一个

代表能否移动移动的字符一定是0或者1  

 

Output 首先输出case数,接着输出最小的移动步数使得游戏达到目标状态(见sample);

数据保证有解。  

 

Sample Input 2 GGGG0 GGGG0 GGGG0 OGOO0 GGGG0 OGOO0 OOOO0 OGGG1 OOOO0 RRRR0 OOOO0 OOOO0 OOOO0 OOOO0 OOOO0 OOOO0 OOOO0 RRRR0  

 

Sample Output Case #1: 5 Case #2: 2  

 

Source
2013腾讯编程马拉松复赛第一场(3月29日)  

 

Recommend liuyiding

 

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4531

这题很明显就是bfs。

但是比赛的时候被坑死了,错了无数次。

用string就超时,只能改成char了,看来string慢很多啊。

 

我是用int表示状态的,初始状态就是012345678.这样用个map就可以对状态判重了。

至于判断是不是符合题意的状态,我用的是并查集来判断的。每个格子上下左右四个三角标号0、1、2、3.这样总共4*9=36个点。根据情况去合并,最后判断相同颜色是不是根相同即可。合并的时候,一个格子里的四条边可能合并,格子间12条边可能合并。

状态转移就是6种情况。分别对每一行、每一列操作。。

 

这题写挫了要么MLE,要么TLE,很难搞。。。。。。

 

/*
*HDU 4531
*BFS
*注意判重
*/


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <iostream>
using namespace std;

char str[3][3][6];
char g[3][3][6];

map<int,int>mp;
queue<int>q;
bool move[6];//是否可以移动,0~5对应1~3行,1~3列

//并查集判断连通
int F[50];
int find(int x)
{
    if(F[x]==-1)return x;
    return F[x]=find(F[x]);
}
void bing(int x,int y)
{
    int t1=find(x);
    int t2=find(y);
    if(t1!=t2)F[t1]=t2;
}
//并查集判断是不是连通
bool judge(int state)//判断状态state是不是连通
{
    char temp[10];
    int t[10];
    sprintf(temp,"%09d",state);
    for(int i=0;i<9;i++)t[i]=temp[i]-'0';
    for(int i=0;i<3;i++)
      for(int j=0;j<3;j++)
      {
          int p=t[3*i+j];
          int x=p/3;
          int y=p%3;
          strcpy(g[i][j],str[x][y]);
      }
    memset(F,-1,sizeof(F));
    for(int i=0;i<3;i++)
      for(int j=0;j<3;j++)
      {
          if(g[i][j][0]==g[i][j][2])bing(12*i+4*j,12*i+4*j+2);
          if(g[i][j][0]==g[i][j][3])bing(12*i+4*j,12*i+4*j+3);
          if(g[i][j][1]==g[i][j][2])bing(12*i+4*j+1,12*i+4*j+2);
          if(g[i][j][1]==g[i][j][3])bing(12*i+4*j+1,12*i+4*j+3);
      }
    for(int i=0;i<3;i++)
    {
        if(g[i][0][3]==g[i][1][2])bing(12*i+3,12*i+4+2);
        if(g[i][1][3]==g[i][2][2])bing(12*i+4+3,12*i+8+2);
    }
    for(int j=0;j<3;j++)
    {
        if(g[0][j][1]==g[1][j][0])bing(4*j+1,12+4*j+0);
        if(g[1][j][1]==g[2][j][0])bing(12+4*j+1,24+4*j+0);
    }
    int R=-1,G=-1,B=-1,O=-1;
    for(int i=0;i<3;i++)
      for(int j=0;j<3;j++)
        for(int k=0;k<4;k++)
        {
            int t1=find(12*i+4*j+k);
            if(g[i][j][k]=='R')
            {
                if(R==-1)R=t1;
                else if(t1!=R)return false;
            }
            else if(g[i][j][k]=='G')
            {
                if(G==-1)G=t1;
                else if(t1!=G)return false;
            }
            else if(g[i][j][k]=='B')
            {
                if(B==-1)B=t1;
                else if(t1!=B)return false;
            }
            else
            {
                if(O==-1)O=t1;
                else if(t1!=O)return false;
            }
        }
    return true;
}
int bfs()
{
    mp.clear();
    while(!q.empty())q.pop();
    int tmp,now;
    char ss1[10],ss2[10];
    tmp=12345678; //初始是012345678
    mp[tmp]=0;
    q.push(tmp);
    while(!q.empty())
    {
        tmp=q.front();
        q.pop();
        if(judge(tmp))return mp[tmp];
        sprintf(ss1,"%09d",tmp);

        for(int i=0;i<3;i++)
          for(int j=0;j<3;j++)
          {
              int t=ss1[3*i+j]-'0';
             strcpy(g[i][j],str[t/3][t%3]);
          }
        //第一行的左右移动
        if(move[0])
        {
            strcpy(ss2,ss1);
            ss2[0]=ss1[1];
            ss2[1]=ss1[2];
            ss2[2]=ss1[0];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

            ss2[0]=ss1[2];
            ss2[1]=ss1[0];
            ss2[2]=ss1[1];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

        }

        //第二行的左右移动
        if(move[1])
        {
            strcpy(ss2,ss1);
            ss2[3]=ss1[4];
            ss2[4]=ss1[5];
            ss2[5]=ss1[3];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }
            ss2[3]=ss1[5];
            ss2[4]=ss1[3];
            ss2[5]=ss1[4];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }
        }


        //第三行的左右移动
        if(move[2])
        {
            strcpy(ss2,ss1);
            ss2[6]=ss1[7];
            ss2[7]=ss1[8];
            ss2[8]=ss1[6];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

            ss2[6]=ss1[8];
            ss2[7]=ss1[6];
            ss2[8]=ss1[7];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

        }


        //第一列的左右移动
        if(move[3])
        {
            strcpy(ss2,ss1);
            ss2[0]=ss1[3];
            ss2[3]=ss1[6];
            ss2[6]=ss1[0];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

            ss2[0]=ss1[6];
            ss2[3]=ss1[0];
            ss2[6]=ss1[3];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

        }

        //第二列的左右移动
        if(move[4])
        {
            strcpy(ss2,ss1);
            ss2[1]=ss1[4];
            ss2[4]=ss1[7];
            ss2[7]=ss1[1];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

            ss2[1]=ss1[7];
            ss2[4]=ss1[1];
            ss2[7]=ss1[4];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

        }

        //第三列的左右移动
        if(move[5])
        {
            strcpy(ss2,ss1);
            ss2[2]=ss1[5];
            ss2[5]=ss1[8];
            ss2[8]=ss1[2];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }

            ss2[2]=ss1[8];
            ss2[5]=ss1[2];
            ss2[8]=ss1[5];
            now=0;
            for(int i=0;i<9;i++)
            {
                now*=10;
                now+=ss2[i]-'0';
            }
            if(mp.find(now)==mp.end())
            {
                mp[now]=mp[tmp]+1;
                q.push(now);
            }
        }

    }
    return -1;
}

int main()
{
    int T;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        iCase++;
        printf("Case #%d: ",iCase);
        for(int i=0;i<6;i++)move[i]=true;
        for(int i=0;i<3;i++)
          for(int j=0;j<3;j++)
          {
              scanf("%s",&str[i][j]);
              if(str[i][j][4]=='1')//所在的列和行不能移动
              {
                  move[i]=false;
                  move[3+j]=false;
              }
          }
        printf("%d\n",bfs());
    }
    return 0;
}

 

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/archive/2013/03/30/2990176.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞