uva 10274 Fans and Gems(隐式图搜索+模拟)
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(隐式图搜索+模拟)的更多相关文章
- 紫书 例题 11-6 UVa 658 (状态压缩+隐式图搜索+最短路)
这道题用到了很多知识点, 是一道好题目. 第一用了状态压缩, 因为这里最多只有20位, 所以可以用二进制来储存状态 (要对数据范围敏感), 然后 涉及到了一些位运算. 第二这里是隐式 ...
- 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& ...
- 【uva 658】It's not a Bug, it's a Feature!(图论--Dijkstra或spfa算法+二进制表示+类“隐式图搜索”)
题意:有N个潜在的bug和m个补丁,每个补丁用长为N的字符串表示.首先输入bug数目以及补丁数目.然后就是对M个补丁的描述,共有M行.每行首先是一个整数,表明打该补丁所需要的时间.然后是两个字符串,第 ...
- [HNOI2006]最短母串问题 --- AC自动机 + 隐式图搜索
[HNOI2006]最短母串问题 题目描述: 给定n个字符串(S1,S2.....,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,......,Sn)都是T的子串. 输入格式: 第 ...
- 洛谷 P2622 关灯问题II【状压DP;隐式图搜索】
题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时 ...
- uva 310 L--system(隐式图搜索+字符串处理)
L-system A D0L (Deterministic Lindenmayer system without interaction) system consists of a finite ...
- 状态转移的最短路 隐式图搜索 UVA 658
紫书365 题目大意:给你n个全都是bug的东西,然后每次可以修复,给你修复前后的状态,问最后如果能把bug全都修复,最少需要多少时间. 思路:从最初状态开始,然后枚举bug即可. 表示priorit ...
- UVA - 10603 Fill(隐式图搜索)
题目大意:经典的倒水问题. 给你三个瓶子,体积为a,b,c. 刚開始a.b是空的,c是满的,如今要求你到出体积为d的水.倒水的规则为,要么倒水方为空,要么接水方满 问倒到容量为d时,倒水的最小体积是多 ...
- uva-321-暴力枚举-隐式图搜索
题意:给你n个房间,有许多灯的控制开关,i房间灯的开关在j房间,未开灯的房间不能进,i房间和j房间之间如果没有门,也不能从i进入到j,开始房间是1,并且灯是开着的,问你是否能够走到最后一个房间n,并且 ...
随机推荐
- poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)
题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一 ...
- poj 1364 King(差分约束)
题意(真坑):傻国王只会求和,以及比较大小.阴谋家们想推翻他,于是想坑他,上交了一串长度为n的序列a[1],a[2]...a[n],国王作出m条形如(a[si]+a[si+1]+...+a[si+ni ...
- BrowserSync,调试利器--自动刷新(转
---恢复内容开始--- 请想象这样一个场面:你开着两个显示器,一边是IDE里的代码,另一边是浏览器里的你正在开发的应用.此时桌上还放着你的手机,手机里也是这个开发中的应用.然后,你新写了一小段代码, ...
- datatables 参数详解(转)
//@translator codepiano //@blog codepiano //@email codepiano.li@gmail.com //尝试着翻译了一下,难免有错误的地方,欢迎发邮件告 ...
- LeetCode: Maximum Product Subarray && Maximum Subarray &子序列相关
Maximum Product Subarray Title: Find the contiguous subarray within an array (containing at least on ...
- DrawDibDraw函数的使用方法
使用windows的的自带的函数来显示图像可能始终还是绕不开两个概念, 视口和窗口. 视口--- 屏幕上的一个显示用的矩形框. 窗口--- 完整图像上的一个用于取数的矩形框. 屏幕的宽度.高度和视口参 ...
- 视频捕捉全教程(vc+vfw)
目 录 一. 视频捕获快速入门 二.基本的捕获设置 1.设置捕获速度: 2.设置终止捕获 3.捕获的时间限制 三.关于捕获窗口 1.创建一个AVICAP捕获窗口 2.将一个捕获窗口连接至捕获设备 3. ...
- UIView 设置alpha后, 子view也随着变化alpha, 解决方法
// _closeContainerBar.alpha = 0.7; _closeContainerBar.backgroundColor = [[UIColor blackColor] ...
- 【JSP】<meta>标签用法
转载自:http://blog.sina.com.cn/s/blog_65c74cce0102v39z.html 非常感谢这位博主,急着用,改日再细细品味重新整理这篇博文. http-equiv M ...
- java 访问器方法中对象引用的问题
"注意不要编写返回引用可变对象的访问器方法".因为会破坏类的封装性,引用的内容可能会被改变,产生业务逻辑上的错误. 什么是可变对象? 先要搞清楚java中值传递和引用传递的问题,总结如下: 1.对象就 ...