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. Apache端口配置

    找到配置文件 httpd.conf  并用编辑器打开. 在添加端口之前,我们可以查看端口是否已经被开启,命令如下: window查看端口: # 查看所有端口$ netstat -n -a# 查看 80 ...

  2. Codeforces 4538 (状态压缩dp)Little Pony and Harmony Chest

    Little Pony and Harmony Chest 经典状态压缩dp #include <cstdio> #include <cstring> #include < ...

  3. ASP.NET MVC 学习3、Controller左手从Model获取数据,右手传递到View页面

    参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/accessing-your-models-dat ...

  4. UVa 11400 Lighting System Design【DP】

    题意:给出n种灯泡,分别给出它们的电压v,电源费用k,每个灯泡的费用c,和所需灯泡的数量l,问最优方案的费用 看的紫书= = 首先是dp[i]为灯泡1到i的最小费用, dp[i]=min(dp[i], ...

  5. RecyclerView 结合 CardView 使用(二)

    上一篇的基础上,修改了,CardView的布局和点击效果 总结: CardView的奇葩属性 :app:cardPreventCornerOverlap="false" 和园角边框 ...

  6. (转)c & c++内存分配

    一.预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于 数据结构中的栈. ...

  7. 基于RTP的H264视频数据打包解包类

    from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打 ...

  8. [HTML Q&A][转]使pre的内容自动换行

    <pre> 元素可定义预格式化的文本.被包围在 pre 元素中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. <pre> 标签的一个常见应用就是用来表示计算机的源代码 ...

  9. 炮兵阵地(POJ 1185状压dp)

    题意:n*m地图'H'能放'p'不能放,布兵的方格上下左右不能布兵,给你地图求最大布兵数 分析:关系到前两行,所以dp[i][j][k]第i行状态为j,i-1行状态为k时的最大布兵数, 先求出所有可行 ...

  10. 一个可序列化的C#对象,如何转成一个XML格式的文件或字符串【转】

    原文:http://blog.csdn.net/otong/article/details/7894059 序列化或反序列化成一个字符串: 方法一: 序列化: public static string ...