UVa 10274:Fans and Gems, 神牛Rujia Liu的神題(三)

來源:互聯網
上載者:User

題目連結:

UVa :  http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1215

zoj    : http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1237

類型:  隱式圖搜尋+噁心類比+雜湊判重+bfs+dfs

原題:

Tomy's fond of a game called 'Fans and Gems' (also known as Gravnic). In the game, he can use fans to collect gems, but he's satisfied with his play only if all the gems are collected with minimal number of steps. The game is played as following:

There are three kinds of gems, one colored red, one colored green and one colored blue. There are walls in the space, as you see. There are also virtual fans everywhere in the game, but you cannot see them. What you can do each time is to select a DIRECTION to which the fans should blow. There are only four directions possible: UP, DOWN, LEFT and RIGHT. Then, the fans will work, pushing all the gems to fly to the selected direction at the same speed, until they cannot move further(blocked by the wall, other gems or a flyer). Then, if there are some gems touching some same-colored gem(touching means adjacent in one of the four directions), they disappear simultaneously. Note that the fans are still working, so some gems may go on moving in that direction after some gems disappeared. The fans stop working when all the gems cannot move any more, and none of them should disappear. There may be some flyers that can be moved by the fans, but they can NEVER disappear.

You are to write a program that finds the minimal number of operations to make all the gems disappear.

Input

The input file begins with an integer T, indicating the number of test cases. (1<=T<=50) Each test case begins with two integers N, M, indicating the height and width of the map. (1<=N<=12,1<=M<=20) In the following N lines, each line contains M characters describing the map. There is one line after each map, ignore them. Spaces denotes empty square, '#' denotes a wall, '1' denotes a red gem, '2' denotes a green gem, '3' denotes a blue gem, and '@' denotes a flyer. It's guaranteed that the four sides of the map are all walls. There is at least one gem in the map, and no two same-colored gems will touch each other at the beginning of the game.

Output

You should print a single line for each case. If there is a solution, write the shortest operation sequence in a string. The ith character must be from the set {'U','D','L','R'}, describing ith operation. The four characters represent UP, DOWM, LEFT, RIGHT respectively. If there are more than one solution, choose the lexicographical smallest one, if there are no solution, output -1 on the line. When a solution exists, you need only 18 or fewer steps to carry it out.

Sample Input

2
9 8
########
##   1##
##  2  #
#  1  ##
##2   ##
#   1@##
###   ##
#### ###
########

7 8
########
#212121#
#      #
# # # ##
# #    #
#     ##
########
 

Sample Output

LURD
DL

題目大意:

Tomy很喜歡一款遊戲叫做粉絲和寶石(Fans and Gems,第一個單詞不知道該怎麼翻譯), 玩家可以讓粉絲去收集寶石。Tomy希望可以用最少的步數把所有的寶石都收集起來。 遊戲的玩法是這樣的:

寶石有三種:紅,綠,藍, 分別用1,2,3來代替,地圖的四周有牆,地圖中還可能有飛行器,用@代替。  粉絲是虛擬,看不到的,它們在地圖的每一個角落,無處不在。 你每一次可以選擇一個方向(上,下,左,右), 然後這些粉絲就會往這個方向推地圖上的所有寶石和飛行器(其實就是選擇一個方向,然後地圖中所有的寶石和飛行器都會同時往這個方向以相同的速度移動)。當寶石和飛行器碰到牆就會停止下來。 或者遇到了一個已經停止下來的寶石和飛行器,也會停止下來。 在移動的過程中,一旦發現有相同的寶石是相鄰的,那麼相鄰的那些相同寶石都會消失。

分析與總結:

題目倒是挺好玩的,但是……這一題涉及到的類比過程比上一題的噁心程度以指數級增加……

需要類比整個地圖中寶石和飛行器的移動過程,然後還要消除掉相鄰的相同的寶石。

把過程類比好,也就向AC邁出了一大步。  

然後就是像做一般的隱式圖搜尋+雜湊判重一樣。

還有一個需要注意的地方,如果有多種方案,那麼輸出字典序最小的那個, 這樣只需要在搜尋時,方向按照字典序D,L,R, U的順序搜尋下去即可。

WA了一次,原因:

1.  大於18步的就不再考慮。

2. 每一個輸入之後會多出一行無用的, 而且不一定是空行(這個還是看了discuss給的輸入輸出才知道的),要把這一行讀掉。

/*  *  UVa  10274 - Fans and Gems  *  隱式圖搜尋 + BFS + 類比 + 雜湊判重  *  Time: 0.376s (UVa)    590ms(zoj)  *  Author: D_Double  */#include<iostream>  #include<cstring>  #include<cstdio>  using namespace std;  typedef char State[13][21];  State map;  int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};  char dir_name[] = {'D', 'L', 'R', 'U'};  int N,M;              inline void swap(char &ch1, char &ch2){ char t=ch1; ch1=ch2; ch2=t; }        inline bool is_gem_fly(char ch){      if(ch=='1'||ch=='2'||ch=='3'||ch=='@') return true;      return false;  }        // 類比個方向移動過程,注意按字典順序:D,L,R,U  // 本文URL:http://www.bianceng.cn/Programming/sjjg/201410/45633.htminline bool move(State &s, int dir){      bool flag=false;      if(dir==0){ // 下          for(int i=1; i<M-1; ++i){              for(int j=N-1; j>0; --j)if(s[j][i]==' '){                  int k = j-1;                  while(s[k][i]==' ') --k;                  if(is_gem_fly(s[k][i])){                      swap(s[j][i], s[k][i]); flag=true;                  }                  else                    j=k;              }          }      }      else if(dir==1){ // 左          for(int i=1; i<N-1; ++i){              for(int j=1; j<M-1; ++j)if(s[i][j]==' '){                  int k = j+1;                  while(s[i][k]==' ') ++k;                  if(is_gem_fly(s[i][k])){                      swap(s[i][j], s[i][k]); flag=true;                  }                  else                    j=k;              }          }      }      else if(dir==2){ // 右          for(int i=1; i<N-1; ++i){              for(int j=M-1; j>1; --j)if(s[i][j]==' '){                  int k = j-1;                  while(s[i][k]==' ') --k;                  if(is_gem_fly(s[i][k])){                      swap(s[i][j], s[i][k]); flag=true;                  }                  else                    j=k;              }          }      }      else if(dir==3){ // 上          for(int i=1; i<M-1; ++i){              for(int j=1; j<N-1; ++j)if(s[j][i]==' '){                  int k = j+1;                  while(s[k][i]==' ')++k;                  if(is_gem_fly(s[k][i])){                      swap(s[j][i], s[k][i]); flag=true;                  }                  else                    j=k;              }          }      }      if(flag)return true;      return false;  }        void dfs(State &s, char ch, int x, int y){ // 消除相同的寶石      s[x][y] = ' ';      for(int i=0; i<4; ++i){          int dx=x+dir[i][0], dy=y+dir[i][1];          if(s[dx][dy]==ch)              dfs(s, ch, dx, dy);      }  }        inline bool remove(State &s){      bool ok=false;      for(int i=1; i<N-1; ++i){          for(int j=1; j<M-1; ++j)if(is_gem_fly(s[i][j]) && s[i][j]!='@'){              bool flag=false;              for(int k=0; k<4; ++k){                  int dx=i+dir[k][0], dy=j+dir[k][1];                  if(dx>=0 && dx<N && dy>=0 && dy<M && s[i][j]==s[dx][dy]){                      flag=true;                       break;                  }              }              if(flag){                  ok = true;                   dfs(s,s[i][j],i,j);              }          }      }      if(ok) return true;      return false;  }        inline void run(State &s, int dir){  // 往哪個方向的步驟      while(move(s, dir)){          remove(s);      }  }        const int MAXN = 100000;  const int HashSize = 1000003;  State que[MAXN];  int head[HashSize], next[MAXN], father[MAXN], step[MAXN], ans;  char path[MAXN];        inline void init_lookup_table(){       ans = -1;      father[0]=0;       step[0] = 0;      memset(head, 0, sizeof(head));       memset(que, 0, sizeof(que));  }  inline int hash(State &s){      int seed=131, v=0;      for(int i=0; i<N; ++i){          for(int j=0; j<M; ++j)              v = (v*seed+s[i][j]) & 0x7FFFFFFF;      }      return v%HashSize;  }  bool try_to_insert(int s){      int h = hash(que[s]);      int u = head[h];      while(u){          if(memcmp(que[u], que[s], sizeof(que[s]))==0)return false;          u = next[u];      }      next[s] = head[h];      head[h] = s;      return true;  }        inline bool is_ok(State &s){      for(int i=1; i<N-1; ++i){          for(int j=1; j<M-1; ++j)              if(s[i][j]=='1'||s[i][j]=='2'||s[i][j]=='3')return false;      }      return true;  }        bool bfs(){      init_lookup_table();      int front=0, rear=1;      memcpy(que[0], map, sizeof(map));      try_to_insert(0);            while(front < rear){          State &s = que[front];          if(step[front] > 18){              ++front; continue;          }          if(is_ok(s)){              ans = front;              return true;          }          for(int i=0; i<4; ++i){              State &t = que[rear];              memcpy(t, s, sizeof(s));              run(t, i);              if(try_to_insert(rear)){                  step[rear] = step[front]+1;                  father[rear] = front;                  path[rear] = dir_name[i];                  ++rear;              }          }          ++front;      }      return false;  }        void print_path(int cur){      if(cur){          print_path(father[cur]);          printf("%c", path[cur]);      }  }        int main(){      int T;      char str[1000];      scanf("%d%*c",&T);      while(T--){          scanf("%d%d%*c",&N,&M);          for(int i=0; i<N; ++i)              gets(map[i]);           gets(str);          if(!bfs())              printf("-1\n");          else{              print_path(ans);              printf("\n");          }      }      return 0;  }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.