zoukankan      html  css  js  c++  java
  • 蓝桥杯——九宫重排、青蛙跳杯子

    1.历届试题 九宫重排  

    时间限制:1.0s   内存限制:256.0MB
          
    问题描述
      如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

      我们把第一个图的局面记为:12345678.
      把第二个图的局面记为:123.46758
      显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
      本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
    输入格式
      输入第一行包含九宫的初态,第二行包含九宫的终态。
    输出格式
      输出最少的步数,如果不存在方案,则输出-1。
    样例输入
    12345678.
    123.46758
    样例输出
    3
    样例输入
    13524678.
    46758123.
    样例输出
    22
    思考过程:

    九宫格数字的移动,其实是由空格移动造成的,所以,站在空格的角度上,将空格当作运动的点,有四种运动方向:前后左右。以前迷宫问题, 就是起点走到终点,深度搜索(队列),最先到达终点时的步数,就是最短路径;九宫重排问题一样,用字符串表示九宫格的状态,遍历的过程中,当 到达的状态和目标状态一致时结束,但是怎么避免老是走重复的路呢(排重)?那就需要将过程中的状态全部记录下来,每走到新的状态,比较一下先前是否出现过,若出现过,就停止走这条路,即不让这一状态入队列即可。将先前的状态放入set容器可以很快速知道是否出现过。

    第一次 TLE 运行超时了,60分;

    第二次 TLE 运行超时了,80分, 将操作(1)、(2)交换位置,要986ms,说明没有在根源上减少时间。

    第三次,100昏,将结构体增加'.'(空格)的坐标,省去每次找坐标的时间。

    <c++代码>
     1 #include<stdio.h>
     2 #include<set>
     3 #include<queue>
     4 #include<string.h>
     5 #include<string>
     6 using namespace std;
     7 struct node
     8 {
     9     int step,pos_x,pos_y;
    10     char str[15];
    11 };
    12 char str1[15],str2[15];//初始状态、目标状态
    13 int D[4][2]= {-1,0,1,0,0,-1,0,1};
    14 set<string> Set;//定义一个string类型的set容器,存放九宫格的状态
    15 queue<node> que;//定义一个队列,存放行走过程中的状态,每一个node包含达到此状态的步数step、和当时的状态
    16 int blank_pos(char *str) //空格的位置
    17 {
    18     int l=strlen(str);
    19     for(int i=0; i<l; i++)
    20     {
    21         if(str[i]=='.')
    22             return i;
    23     }
    24 }
    25 int bfs()
    26 {
    27     char next_str[15];
    28     node n,new_node;
    29     int pos,pos_x,pos_y,next_x,next_y,next_pos;
    30     while(!que.empty())
    31     {
    32         n=que.front();//队首出队
    33         que.pop();
    34         for(int i=0; i<4; i++) //空格往四个方向行走
    35         {
    36             strcpy(next_str,n.str);//将来next_str要在n.str的基础上改动,但是n.str一直不能动,因为是四个方向共用的
    37             next_x=n.pos_x+D[i][0];
    38             next_y=n.pos_y+D[i][1];
    39             if(next_x>=0&&next_x<=2&&next_y>=0&&next_y<=2) //将要走的那一步符合要求
    40             {
    41                 //将接下来的状态表示出来(空格上的’0‘ 变为 (next_x,next_y)上的字符,(next_x,next_y)变成空格;查看set里是否有这个状态,若有就不走这一步,避免重复)
    42                 pos=n.pos_x*3+n.pos_y;
    43                 next_pos=next_x*3+next_y;//新空格位置
    44                 next_str[next_pos]='.';
    45                 next_str[pos]=n.str[next_pos];
    46 //判重
    47                 if(Set.find(next_str)==Set.end()) //表示没有找到重的
    48                 {
    49                     new_node.step=n.step+1;
    50                     //(1)查看着个状态是不是目标状态
    51                     if(!strcmp(next_str,str2)) //即得到了目标状态
    52                     {
    53                         return new_node.step;
    54                     }
    55                     //(2)将新的状态记录在队列和Set里
    56                     strcpy(new_node.str,next_str);
    57                     new_node.pos_x=next_x;
    58                     new_node.pos_y=next_y;
    59                     que.push(new_node);
    60                     Set.insert(next_str);
    61                 }
    62             }
    63         }
    64     }
    65     return -1;
    66 }
    67 int main()
    68 {
    69 //输入
    70     node n;
    71     int min,pos;
    72     scanf("%s",str1);
    73     scanf("%s",str2);//目标
    74     if(!strcmp(str1,str2)) //即得到了目标状态
    75     {
    76         printf("%d",0);
    77     }
    78     else
    79     {
    80 //初始状态放入队列和set容器
    81         pos=blank_pos(str1);//找'.'的位置
    82         n.pos_x=pos/3;
    83         n.pos_y=pos%3;
    84         n.step=0;
    85         strcpy(n.str,str1);
    86         que.push(n);
    87         Set.insert(n.str);
    88         min=bfs();//广搜,找出最少步骤
    89         printf("%d",min);
    90     }
    91     return 0;
    92 }
    View Code

    2.历届试题 青蛙跳杯子  

    时间限制:1.0s   内存限制:256.0MB
        
    问题描述
      X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色。
      X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去。
      如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙。


      *WWWBBB


      其中,W字母表示白色青蛙,B表示黑色青蛙,*表示空杯子。


      X星的青蛙很有些癖好,它们只做3个动作之一:
      1. 跳到相邻的空杯子里。
      2. 隔着1只其它的青蛙(随便什么颜色)跳到空杯子里。
      3. 隔着2只其它的青蛙(随便什么颜色)跳到空杯子里。


      对于上图的局面,只要1步,就可跳成下图局面:


      WWW*BBB


      本题的任务就是已知初始局面,询问至少需要几步,才能跳成另一个目标局面。


      输入为2行,2个串,表示初始局面和目标局面。
      输出要求为一个整数,表示至少需要多少步的青蛙跳。
    样例输入
    *WWBB
    WWBB*
    样例输出
    2
    样例输入
    WWW*BBB
    BBB*WWW
    样例输出
    10
    数据规模和约定
      我们约定,输入的串的长度不超过15
     
     
    思路:和九宫重排一模一样,在九宫重排(60分代码)的代码上稍作改动,

    青蛙跳杯子,感觉和九宫重排很相似,虽然是青蛙在跳,但是可以看成空杯子在跳,有6种跳法:往左一个、往右一个,往左两个、往右两个,往左三个、往右三个。诶等一下!!会不会不只一个空杯子?、这样就不行了,不管了,就先当所有案例的都只有一个空杯子,两个的话,就2*6种跳法?后来提交代码后,发现只用考虑一个空杯子。

    <c++代码>

     1 include<stdio.h>
     2 #include<set>
     3 #include<string>
     4 #include<string.h>
     5 #include<queue>
     6 using namespace std;
     7 struct node{
     8     int step;
     9     char str[20];
    10 };
    11 int D[6]={-1,1,-2,2,-3,3};
    12 int len;//杯子个数
    13 char str1[20],str2[20];//初始状态、目标状态
    14 set<string> Set;//用Set存放跳的过程中的状态
    15 queue<node> que;//node每一次跳跃之后的状态和已经跳跃的步数
    16 int blank_pos(char *str) //空格的位置
    17 {
    18     for(int i=0; i<strlen(str); i++)
    19     {
    20         if(str[i]=='*')
    21             return i;
    22     }
    23 }
    24 int bfs()
    25 {
    26     char next_str[20];
    27     node n,new_node;
    28     int pos,next_pos;
    29     while(!que.empty())
    30     {
    31         n=que.front();//队首出队
    32         //printf("%s
    ",n.str);
    33         que.pop();
    34         //得出'*'的位置
    35         pos=blank_pos(n.str);
    36         for(int i=0; i<6; i++) //*有五种跳法
    37         {
    38             strcpy(next_str,n.str);//将来next_str要在n.str的基础上改动,但是n.str一直不能动,因为是四个方向共用的
    39             next_pos=pos+D[i];
    40             if(next_pos>=0&&next_pos<len) //将要走的那一步符合要求
    41             {
    42                 //将接下来的状态表示出来('*'变为 next_pos上的字符,next_pos上的字符变成'*';查看set里是否有这个状态,若有就不走这一步,避免重复)
    43 
    44                 next_str[next_pos]='*';
    45                 next_str[pos]=n.str[next_pos];
    46 //判重
    47                 if(Set.find(next_str)==Set.end()) //表示没有找到重的
    48                 {
    49                     //将新的状态记录在队列和Set里
    50                     strcpy(new_node.str,next_str);
    51                     new_node.step=n.step+1;
    52                     que.push(new_node);
    53                     Set.insert(next_str);
    54                     //查看着个状态是不是目标状态
    55                     if(!strcmp(next_str,str2)) //即得到了目标状态
    56                     {
    57                         return new_node.step;
    58                     }
    59                 }
    60             }
    61         }
    62     }
    63     return -1;
    64 }
    65 int main(){
    66     node n;
    67     int min;
    68 scanf("%s",str1);
    69     scanf("%s",str2);//目标
    70     len=strlen(str1);
    71     if(!strcmp(str1,str2)) //即得到了目标状态
    72     {
    73         printf("%d",0);
    74     }
    75     else
    76     {
    77 //初始状态放入队列和set容器
    78         n.step=0;
    79         strcpy(n.str,str1);
    80         que.push(n);
    81         Set.insert(n.str);
    82         min=bfs();//广搜,找出最少步骤
    83         printf("%d",min);
    84     }
    85 return 0;
    86 }
    View Code
  • 相关阅读:
    【[USACO08FEB]酒店Hotel】
    【[USACO15JAN]草鉴定Grass Cownoisseur】
    【[USACO09DEC]牛收费路径Cow Toll Paths】
    【[HAOI2009]逆序对数列】
    【Hankson 的趣味题】
    【开车旅行】
    【[ZJOI2006]物流运输】
    【[HNOI2005]狡猾的商人】
    【愤怒的小鸟】
    【[HNOI2015]菜肴制作】
  • 原文地址:https://www.cnblogs.com/li-yaoyao/p/10547359.html
Copyright © 2011-2022 走看看