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,并且 ...
随机推荐
- servlet应用具体实例
web,xml应用文件 1.<filter>参数 <filter> <filter-name>encodingFilter</filter-name> ...
- 安卓学习之--如何关闭所有的activity
根据Activity的声明周期 方法1 我们知道Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标志 Intent ...
- bzoj4025
首先我们要知道,怎么去维护一个是否是二分图 二分图的充要条件:点数>=2且无奇环 重点就是不存在奇环,怎么做呢 考虑随便维护一个图的生成树,不难发现,如果一条边加入后,形成奇环的话就不是二分图 ...
- LA 3135 (优先队列) Argus
将多个有序表合并成一个有序表就是多路归并问题,可用优先队列来解决. #include <cstdio> #include <queue> using namespace std ...
- BZOJ3105: [cqoi2013]新Nim游戏
题解: 线性基?类似于向量上的基底. 此题题解戳这里:http://blog.csdn.net/wyfcyx_forever/article/details/39477673 代码: #include ...
- SQL Server:把CSV文件导入到SQL Server表中
有时候我们可能会把CSV中的数据导入到某个数据库的表中,比如做报表分析的时候. 对于这个问题,我想一点也难不倒程序人员吧!但是要是SQL Server能够完成这个任务,岂不是更好! 对,SQL Ser ...
- Grunt + Bower—前端构建利器(转)
目前比较流行的WEB开发的趋势是前后端分离.前端采用重量级的Javascript框架,比如Angular,Ember等,后端采用restful API的Web Service服务,通过JSON格式进行 ...
- LeetCode: Reverse Words in a String && Rotate Array
Title: Given an input string, reverse the string word by word. For example,Given s = "the sky i ...
- ActionBarSherlock的学习笔记(三) ------------ ActionBarSherlock中的overflow及item的点击事件
定义一个自定义的ActionBar的title,并添加一个overflow的Action Item. 代码实现 如下 : import android.os.Bundle; import and ...
- Android中空格及换行
空两个字符 换行 \n