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. Effective C++学习笔记 条款04:确定对象被使用前已先被初始化

    一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...

  2. 转:表单中Readonly和Disabled的区别(HTML中使用javascript解除禁止input输入框代)

    转:表单中Readonly和Disabled的区别 参考资料: disabled和readonly区别: 参考博文1地址:http://blog.csdn.net/symgdwyh/article/d ...

  3. APIO2015题解

    分组赛讲课讲了APIO2015的题,于是回去就做完了 稍微写一点题解吧 bzoj4069 逐位处理的简单题,然后就是bool型dp 然后a=1 的时候可以把一位状态干掉 当一维状态单调且是bool型d ...

  4. struts2中改变struts.xml默认路径

    struts2.X配置文件默认存放路径在/WEB-INF/classes目录下,即将struts.xml放在src的目录下. 但是为了方便管理,开发人员把struts.xml放到其他位置,处理方法如下 ...

  5. HDU 3746 (KMP求最小循环节) Cyclic Nacklace

    题意: 给出一个字符串,要求在后面添加最少的字符是的新串是循环的,且至少有两个循环节.输出最少需要添加字符的个数. 分析: 假设所给字符串为p[0...l-1],其长度为l 有这样一个结论: 这个串的 ...

  6. SQL复制表及表结构

    复制表结构和数据SQL语句 1:复制表结构及数据到新表 select * into 目的数据库名.dbo.目的表名 from 原表名 select * into my0735home.dbo.info ...

  7. Android开发之WebService介绍

    经常有网友问:“在Android平台如何调用WebService”?经过沟通我发现,甚至有些朋友连什么是WebSerivce都不知道就在问怎么使用,更别说和WebService有关的SOAP.WSDL ...

  8. Raphael绘制圆圈环绕方法

    $scope.toRadians = function (degrees) { return degrees * (Math.PI / 180); } $scope.toDegrees = funct ...

  9. 安装服务Memcached+Nginx+Php linux下安装

    Memcached安装 1.      源码安装libevent(下载地址:http://monkey.org/~provos/libevent/) 2.      源码安装memcached(下载地 ...

  10. Myeclipse中相同变量高亮显示

    不小心搞不显示了,解决: windows/MyEclipse-> preferences-> java-> Editor-> Mark Occurences 勾选即可