Fans and Gems
Input:
 Standard Input
Output: Standard Output

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

___________________________________________________________________________________

题目大意:在一个地图上有若干个宝石,宝石分三类, 相同类的宝石相邻之后可以收取,‘@’代表飞行器(会跟着移动,但是不会消失),地图上每个格子有隐藏的fans,风扇,玩家可以通过操作这些风扇来移动宝石和飞行器,每次只能朝同一个方向移动,直到收集齐所有的宝石,输出字典序最小的路径,无法完成游戏输出-1.

解题思路:首先模拟出宝石移动的函数,以及宝石消除的函数,剩下的全是隐式图搜索的过程了。

#include <stdio.h>
#include <string.h> const int MAXN = 100005;
const int R = 15;
const int C = 22;
const int dir[4][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};
const char sign[5] = "DLRU"; struct Map {
char state[R][C];
char order[C];
int cnt;
}aid, begin;
int sumPace, sumGem;
int r, c; bool isGem(char c) {
if (c > '0' && c < '4' || c == '@')
return true;
return false;
} void flyGem(Map now, int& x, int& y, int d) {
do {
x += dir[d][0];
y += dir[d][1];
}while (!isGem(now.state[x][y]) && now.state[x][y] != '#');
x -= dir[d][0];
y -= dir[d][1];
} void moveGem(Map& now, int d) {
int x, y;
if (d == 0) {
for (int i = r - 1; i >= 0; i--) {
for (int j = 0; j < c; j++) {
if (isGem(now.state[i][j])) {
x = i, y = j;
flyGem(now, x, y, d);
now.state[x][y] = now.state[i][j];
if (x != i || y != j)
now.state[i][j] = ' ';
}
}
}
}
else {
for (int i = 0; i < r; i++) {
if (d == 1) {
for (int j = 0; j < c; j++) {
if (isGem(now.state[i][j])) {
x = i, y = j;
flyGem(now, x, y, d);
now.state[x][y] = now.state[i][j];
if (x != i || y != j)
now.state[i][j] = ' ';
}
}
}
else {
for (int j = c - 1; j >= 0; j--) {
if (isGem(now.state[i][j])) {
x = i, y = j;
flyGem(now, x, y, d);
now.state[x][y] = now.state[i][j];
if (x != i || y != j)
now.state[i][j] = ' ';
}
}
}
}
}
}
///////////////////////////////////////////////////////////
Map que[MAXN];
int head[MAXN], next[MAXN], dist[MAXN]; void inInit() {
memset(head, 0, sizeof(head));
memset(que, 0, sizeof(que));
memcpy(que[1].state, begin.state, sizeof(begin.state));
dist[1] = 0;
} inline int hash(Map &cur){
int seed = 131, v = 0;
for(int i = 0; i < r; ++i){
for(int j = 0; j < c; ++j)
v = (v * seed + cur.state[i][j]) & 0x7FFFFFFF;
}
return v % MAXN;
} bool tryInsert(int cur) {
int h = hash(que[cur]);
int u = head[h];
while (u) {
if (memcmp(que[cur].state, que[u].state, sizeof(que[u].state)) == 0)
return false;
u = next[u];
}
next[cur] = head[h];
head[h] = cur;
return true;
} int dfs(Map& now, int x, int y, int ch) {
int sum = 0;
for (int i = 0; i < 4; i++)
if (ch == now.state[x + dir[i][0]][y + dir[i][1]]) {
now.state[x + dir[i][0]][y + dir[i][1]] = ' ';
sum += dfs(now, x + dir[i][0], y + dir[i][1], ch);
}
return sum + 1;
} int delGem(Map& now) {
int sum = 0;
char ch;
for (int x = 0; x < r; x++) {
for (int y = 0; y < c; y++) {
int flag = 0;
for (int i = 0; i < 4; i++) {
if (now.state[x][y] == now.state[x + dir[i][0]][y + dir[i][1]] && isGem(now.state[x][y]) && now.state[x][y] != '@') {
flag = 1;
ch = now.state[x][y];
now.state[x][y] = ' ';
break;
}
} if (flag)
sum += dfs(now, x, y, ch);
}
}
return sum;
} bool bfs() {
int front = 1, rear = 2, k;
inInit(); while (front < rear) {
Map& now = que[front]; if (dist[front] > 18)
return false;
if (now.cnt == sumGem) {
aid = que[front];
sumPace = dist[front];
return true;
} for (int i = 0; i < 4; i++) {
Map& net = que[rear];
net = now; net.order[dist[front]] = sign[i];
while (1) {
moveGem(net, i);
k = delGem(net);
if (k == 0) break;
else net.cnt += k;
} if (tryInsert(rear)) {
dist[rear] = dist[front] + 1;
rear++;
}
}
front++;
}
return false;
} int main() {
int cas;
char str[1000];
scanf("%d", &cas);
while (cas--) {
// Init;
sumPace = sumGem = 0; // Read;
scanf("%d%d%*c", &r, &c);
for (int i = 0; i < r; i++) {
gets(begin.state[i]);
int len = strlen(begin.state[i]);
for (int j = 0; j < len; j++)
if (begin.state[i][j] > '0' && begin.state[i][j] < '4')
sumGem++;
}
gets(str); if (bfs()) {
aid.order[sumPace] = '\0';
puts(aid.order);
}
else
printf("-1\n");
}
return 0;
}

uva 10274 Fans and Gems(隐式图搜索+模拟)的更多相关文章

  1. 紫书 例题 11-6 UVa 658 (状态压缩+隐式图搜索+最短路)

    这道题用到了很多知识点, 是一道好题目.      第一用了状态压缩, 因为这里最多只有20位, 所以可以用二进制来储存状态 (要对数据范围敏感), 然后 涉及到了一些位运算.     第二这里是隐式 ...

  2. UVa 658 - It's not a Bug, it's a Feature!(Dijkstra + 隐式图搜索)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. 【uva 658】It's not a Bug, it's a Feature!(图论--Dijkstra或spfa算法+二进制表示+类“隐式图搜索”)

    题意:有N个潜在的bug和m个补丁,每个补丁用长为N的字符串表示.首先输入bug数目以及补丁数目.然后就是对M个补丁的描述,共有M行.每行首先是一个整数,表明打该补丁所需要的时间.然后是两个字符串,第 ...

  4. [HNOI2006]最短母串问题 --- AC自动机 + 隐式图搜索

    [HNOI2006]最短母串问题 题目描述: 给定n个字符串(S1,S2.....,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,......,Sn)都是T的子串. 输入格式: 第 ...

  5. 洛谷 P2622 关灯问题II【状压DP;隐式图搜索】

    题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时 ...

  6. uva 310 L--system(隐式图搜索+字符串处理)

     L-system  A D0L (Deterministic Lindenmayer system without interaction) system consists of a finite ...

  7. 状态转移的最短路 隐式图搜索 UVA 658

    紫书365 题目大意:给你n个全都是bug的东西,然后每次可以修复,给你修复前后的状态,问最后如果能把bug全都修复,最少需要多少时间. 思路:从最初状态开始,然后枚举bug即可. 表示priorit ...

  8. UVA - 10603 Fill(隐式图搜索)

    题目大意:经典的倒水问题. 给你三个瓶子,体积为a,b,c. 刚開始a.b是空的,c是满的,如今要求你到出体积为d的水.倒水的规则为,要么倒水方为空,要么接水方满 问倒到容量为d时,倒水的最小体积是多 ...

  9. uva-321-暴力枚举-隐式图搜索

    题意:给你n个房间,有许多灯的控制开关,i房间灯的开关在j房间,未开灯的房间不能进,i房间和j房间之间如果没有门,也不能从i进入到j,开始房间是1,并且灯是开着的,问你是否能够走到最后一个房间n,并且 ...

随机推荐

  1. Error Curves(2010成都现场赛题)

    F - Error Curves Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Descript ...

  2. uva12230Crossing Rivers

    数学期望. 过每条河的时间的可能在[L/v,3*L/v]间均匀分布,数学期望为2*L/v. 然后在加上在陆上走的时间. #include<cstdio> #include<algor ...

  3. iOS开发:mac使用svn管理项目

    记录mac下常用的svn命令: 1.检出项目: svn checkout .../svn/projectName --username=xxx --password=xxx //将ip换成svn服务器 ...

  4. UVa 1220 (树的最大独立集) Party at Hali-Bula

    题意: 有一棵树,选出尽可能多的节点是的两两节点不相邻,即每个节点和他的子节点只能选一个.求符合方案的最大节点数,并最优方案判断是否唯一. 分析: d(u, 0)表示以u为根的子树中,不选u节点能得到 ...

  5. Make AngularJS $http service behave like jQuery.ajax()(转)

    There is much confusion among newcomers to AngularJS as to why the $http service shorthand functions ...

  6. 开源的rtsp实现

    开源的rtsp实现                            ============== -- by BeagleTam                                  ...

  7. PNG文件结构分析 ---Png解析

    PNG文件结构分析 ---Png解析   为了实现更高级的应用,我们必须充分挖掘PNG的潜力. PNG的文件结构 根据PNG文件的定义来说,其文件头位置总是由位固定的字节来描述的:   十进制数 13 ...

  8. cocoapods 终极方案

    最近各种错误, 全部刷新 再说 sudo gem install -n /usr/local/bin cocoapods $ sudo gem update --system // 先更新gem $ ...

  9. 是时候学习Android分屏开发了

    今年Google发布了Android N,Android N新增了不少功能,最受关注的自然就是分屏了. 这一功能对国内的很多手机用户并不陌生,其实很多第三方系统早已经实现了这一功能,如EMUI,Fly ...

  10. 【转】MegaSAS RAID卡 BBU Learn Cycle周期的影响

    http://ju.outofmemory.cn/entry/140 背景 最近遇到有些带MegaSAS RAID卡的服务器,在业务高峰时突然IO负载飚升得很高,IO性能急剧下降,查了日志及各种设置最 ...