题目链接:uva 589 - Pushing Boxes
题目大意:推箱子游戏,工人移动用小写,推动箱子用大写,给出推动箱子最少的方法,不用字典序。
解题思路:这题写了一天,一开始考虑到直接bfs,记录箱子和工人的位置以及推动箱子的次数作为状态,结果写好后超时,才发现如果不加推动箱子的次数的话,会将大部分情况合并,时间会减少很多,但是第4组样例会过不了(考虑总步数最少的情况,题目要求推动箱子的次数最少)。
超时代码
#include <stdio.h>
#include <string.h>
#include <set>
#include <queue>
using namespace std;
const int N = 30;
const int d[4][2] = { {0, 1}, {1, 0}, {-1, 0}, {0, -1}};
const char sign[N] = "esnwESNW";
struct point {
int x, y;
friend bool operator < (const point& a, const point& b) {
if (a.x != b.x) return a.x < b.x;
return a.y < b.y;
}
friend bool operator == (const point& a, const point& b) {
return a.x == b.x && a.y == b.y;
}
};
struct state {
int cnt;
point you, blo;
queue<int> path;
friend bool operator < (const state& a, const state& b) {
if (a.cnt != b.cnt) return a.cnt < b.cnt;
if (a.you == b.you) return a.blo < b.blo;
return a.you < b.you;
}
};
int r, c;
char g[N][N];
state s;
set<state> v;
void init() {
int flag = 0;
s.cnt = 0;
v.clear();
while (!s.path.empty()) s.path.pop();
for (int i = 0; i < r; i++) gets(g[i]);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (g[i][j] == 'S') {
s.you.x = i; s.you.y = j;
flag++;
} else if (g[i][j] == 'B') {
s.blo.x = i; s.blo.y = j;
flag++;
}
if (flag == 2) break;
}
}
}
bool bfs() {
set<state>::iterator it;
queue<state> que;
que.push(s);
bool flag = true;
state u, k, ans;
ans.cnt = N * N;
while (!que.empty()) {
u = que.front(); que.pop();
for (int i = 0; i < 4; i++) {
k = u;
k.you.x = u.you.x + d[i][0];
k.you.y = u.you.y + d[i][1];
if (k.cnt >= ans. cnt) continue;
if (k.you == u.blo) {
k.blo.x = u.blo.x + d[i][0];
k.blo.y = u.blo.y + d[i][1];
if (k.blo.x < 0 || k.blo.x >= r || k.blo.y < 0 || k.blo.y >= c) continue;
if (g[k.blo.x][k.blo.y] == '#') continue;
k.path.push(i+4);
k.cnt = u.cnt + 1;
it = v.find(k);
if (g[k.blo.x][k.blo.y] == 'T') {
if (k.cnt < ans.cnt) {
ans = k; flag = false;
}
} else if (it == v.end()) {
v.insert(k);
que.push(k);
}
} else {
if (k.you.x < 0 || k.you.x >= r || k.you.y < 0 || k.you.y >= c) continue;
if (g[k.you.x][k.you.y] == '#') continue;
k.path.push(i);
it = v.find(k);
if (it == v.end()) {
v.insert(k);
que.push(k);
}
}
}
}
if (!flag) {
while (!ans.path.empty()) {
printf("%c", sign[ans.path.front()]);
ans.path.pop();
}
printf("\n");
}
return flag;
}
int main() {
int cas = 1;
while (scanf("%d%d%*c", &r, &c), r + c) {
init();
printf("Maze #%d\n", cas++);
if (bfs()) printf("Impossible.\n");
printf("\n");
}
return 0;
}
后来想到,BFS就是用来解决步数最少的问题,那我直接对木块的移动进行BFS,每找到一条路就进行判断,看工人是否可以按照木块的移动来推箱子(即能否移动到箱子移动的反方向一格又是一层bfs)。写好后试了一下全空的20*20,结果超时了,因为bfs会将所有可能全部考虑,但是又不能说只找一条(因为这条可能不行),用dfs的话又不能保证最短,还是要全部情况考虑。所以我想了一个优化,对于每个位置,记录移动到的最短步数,大于这个步数的话就不再考虑。
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
const int N = 30;
const int M = 10000;
const int INF = 0x3f3f3f3f;
const int d[4][2] = { {0, 1}, {1, 0}, {-1, 0}, {0, -1}};
const char sign[N] = "esnwESNW";
struct point {
int x, y;
};
struct state {
int x, y;
int cnt;
vector<int> rec;
void clear() {
x = y = -1;
cnt = 0;
rec.clear();
}
};
int r, c;
state s, b;
char g[N][N];
void init() {
int flag = 0;
s.clear();
b.clear();
for (int i = 0; i < r; i++) gets(g[i]);
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (g[i][j] == 'S') {
s.x = i, s.y = j;
flag++;
} else if (g[i][j] == 'B') {
b.x = i, b.y = j;
flag++;
}
if (flag == 2) break;
}
}
}
bool bfs(point p, point q, point e, int* ans) {
queue<point> que;
point u, k;
int G[N][N]; memset(G, -1, sizeof(G));
int vis[M]; memset(vis, 0, sizeof(vis));
que.push(p);
while (!que.empty()) {
u = que.front(); que.pop();
if (u.x == e.x && u.y == e.y) {
int xi = u.x, yi = u.y;
while (G[xi][yi] != -1) {
int& dir = G[xi][yi];
vis[++vis[0]] = dir;
xi += d[3-dir][0]; yi += d[3-dir][1];
}
for (int i = vis[0]; i; i--) ans[++ans[0]] = vis[i];
return false;
}
for (int i = 0; i < 4; i++) {
k.x = u.x + d[i][0]; k.y = u.y + d[i][1];
if (k.x < 0 || k.x >= r || k.y < 0 || k.y >= c) continue;
if ((k.x == q.x && k.y == q.y) || (k.x == p.x && k.y == p.y)) continue;
if (g[k.x][k.y] == '#' || G[k.x][k.y] != -1) continue;
G[k.x][k.y] = i;
que.push(k);
}
}
return true;
}
bool judge(state k) {
int ans[M];
memset(ans, 0, sizeof(ans));
int n = k.rec.size();
point p, q, aid;
p.x = s.x; p.y = s.y;
q.x = b.x; q.y = b.y;
for (int i = 0; i < n; i++) {
int dir = k.rec[i];
aid.x = q.x + d[3-dir][0]; aid.y = q.y + d[3-dir][1];
if (bfs(p, q, aid, ans)) return false;
ans[++ans[0]] = dir + 4;
p = q;
q.x += d[dir][0]; q.y += d[dir][1];
}
for (int i = 1; i <= ans[0]; i++) printf("%c", sign[ans[i]]);
printf("\n");
return true;
}
bool solve() {
queue<state> que;
state u, k;
que.push(b);
int v[N][N]; memset(v, INF, sizeof(v));
while (!que.empty()) {
u = que.front(); que.pop();
for (int i = 0; i < 4; i++) {
int p = u.x + d[3-i][0], q = u.y + d[3-i][1];
if (p < 0 || p >= r || q < 0 || q >= c || g[p][q] == '#') continue;
k = u;
k.x += d[i][0]; k.y += d[i][1];
if (k.x < 0 || k.x >= r || k.y < 0 || k.y >= c || g[k.x][k.y] == '#') continue;
if (g[k.x][k.y] == 'T') {
k.rec.push_back(i);
if (judge(k)) return false;
} else {
k.cnt++;
if (k.cnt >= v[k.x][k.y]) continue;
v[k.x][k.y] = k.cnt;
k.rec.push_back(i);
que.push(k);
}
}
}
return true;
}
int main() {
int cas = 1;
while (scanf("%d%d%*c", &r, &c), r + c) {
init();
printf("Maze #%d\n", cas++);
if (solve()) printf("Impossible.\n");
printf("\n");
}
return 0;
}
分享到:
相关推荐
3D-visual-pushing-grasping.zip,通过深度强化学习,训练机器人代理学习计划推动和抓取操作动作。,3D建模使用专门的软件来创建物理对象的数字模型。它是3D计算机图形的一个方面,用于视频游戏,3D打印和VR,以及其他...
Android Programming - Pushing the Limits- Hellman, Erik
3ds Max角色绑定教程-Pushing Your Character Rigs Beyond the Basics in 3ds Max;
AR and VR are revolutionary interfacesSharing many of the same underlying techno
Go above and beyond those stop-gaps and step-by-steps with Pushing Pixels, the real-world guide to developing dynamic and fun content from conception to deployment. Whether you are animating for a ...
https://github.com/andyzeng/visual-pushing-grasping/raw/master/images/self-supervision.gif 视觉推送和抓取工具箱 视觉推动和抓取 (VPG) 是一种训练机器人代理学习如何规划互补推动和抓取动作以进行操作的方法...
欢迎USER_NAME, 这是Gitpod的代码学院学生模板。 我们已经预装了您入门所需的所有工具。 您可以安全地删除此README.md文件,或为您自己的项目进行更改。 不过,请至少阅读一次! 它包含有关Gitpod和我们使用的扩展...
Get ready to create killer apps for iPad and iPhone on the new iOS 7!...iOS 7 Programming: Pushing the Limits will help you develop applications that take full advantage of everything iOS 7 has to offer.
git-exercise_pushing
iOS 6 Programming Pushing the Limits英文版,
解压后获得文件:《iOS 7 Programming Pushing the Limits》.pdf 全高清文字版非图片扫描版,完整!! 其中的一些目录: Part I What’s New? C h a p t e r 1 The Brand New Stuff The New UI …… Enhancements to...
iOS 7 Programming Pushing the Limits Rob Napier Mugunth Kumar ISBN: 978 1 118 81834 3 504 pages February 2014 iOS 7 Programming Pushing the Limits 1118818342 cover image Read an Excerpt Description ...
运用有机化学反应机理研究手法,对无机化学中涉及到的反应进行机理化描述
iOS.5.Programming.Pushing.the.Limits.Developing.Extraordinary.Mobile.Apps.for.Apple.iPhone.iPad.and.iPod.Touch.Wiley
在普通编程的基础上,如何最大限度的使用ios5和利用资源.
资源分类:Python库 所属语言:Python 资源全名:pushing_outshoot_unfold-0.0.3.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
Pushing服务的Icinga通知提供程序该Perl脚本旨在替代任何通知提供程序。 它支持每个用户的API密钥配置。 notify-by-pushovernotify-by-pushover是为 + 。 注意:目前不支持flapping通知。要求具有以下模块的Perl URI...
精品iOS开发书籍,内容十分深入,适合高端进阶
iOS7 Programming Pushing the Limits epub版本