A - Maze
东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。
Input
输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
Output
输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。
Sample Input0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0
Sample Output(0, 0)
(1, 0)
(2, 0)
(3, 0)
(3, 1)
(3, 2)
(2, 2)
(1, 2)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)
Hint
坐标(x, y)表示第x行第y列,行、列的编号从0开始,且以左上角为原点。
另外注意,输出中分隔坐标的逗号后面应当有一个空格。
分析和思路
读入的是一个5*5矩阵,我建立一个7*7的,第0行、第6行、第0列、第6列赋值为1,表示四边都是墙壁。其余先赋值为0,等待读入。
采用BFS的思路,从起点(或者终点)开始,访问一个位置可以访问但没访问过的点,一旦访问,把visit数组的相应位置改写为1,之后不再访问,将这一位置的“父亲”记为上一个点,如此往复,直到访问到最后一个点。
输出时,逐行输出。
#include<iostream> #include<queue> using namespace std; int maze[7][7];//迷宫,包括四面的墙壁 int visit[7][7];//记录是否访问 struct Point { int x; int y; Point() :x(0), y(0) {}; Point(int _x, int _y) :x(_x), y(_y) {}; }; Point parent[7][7]; bool bfs(Point& pb, Point& pe) { queue<Point> que; int run[][2] = { {0,-1},{0,1},{1,0},{-1,0} }; parent[pb.x][pb.y] = pb; que.push(pb); while (!que.empty()) { Point temp = que.front(); que.pop(); visit[temp.x][temp.y] = 1; if (temp.x == pe.x && temp.y == pe.y) return true; for (int i = 0; i < 4; ++i) { Point temp2(temp.x + run[i][0], temp.y + run[i][1]); if (maze[temp2.x][temp2.y] == 0 && visit[temp2.x][temp2.y] == 0) { que.push(temp2); parent[temp2.x][temp2.y] = temp; } } } return false; } int main() { for (int i = 0; i < 7; ++i) maze[0][i] = 1; for (int i = 0; i < 7; ++i) maze[i][0] = 1; for (int i = 0; i < 7; ++i) maze[6][i] = 1; for (int i = 0; i < 7; ++i) maze[i][6] = 1; // memset(visit, 0, sizeof(visit)); for (int i = 1; i <= 5; ++i) for (int j = 1; j <= 5; ++j) cin >> maze[i][j]; Point g_begin(1, 1), g_end(5, 5); if (bfs(g_end, g_begin)) { Point a(1, 1); cout << "(0, 0)" << endl; while (a.x != 5 || a.y != 5) { a = parent[a.x][a.y]; cout << '(' << a.x - 1 << ", " << a.y - 1 << ')' << endl; } } return 0; }
B - Pour Water
Input
Output
Sample Input
2 7 5 2 7 4
Sample Output
fill B pour B A success fill A pour A B fill A pour A B success
Notes如果你的输出与Sample Output不同,那没关系。对于某个"A B C"本题的答案是多解的,不能通过标准的文本对比来判定你程序的正确与否。 所以本题由 SPJ(Special Judge)程序来判定你写的代码是否正确。
分析和思路
两个杯子,共有六种操作:A倒入B,B倒入A,A倒空,B倒空,A装满,B装满。
思路和之前的迷宫一样,区别是,迷宫每个状态下,接下来有四种选择,而倒水问题接下来有六种 选择。仍然使用类似于迷宫的解决方案,使用visit数组表示实现过的状态,这一状态如果不满足条件,就变为下一状态...
A倒入B,分为能装满和装不满两种状态,如果B瓶装不下,A剩下x+y-B,否则A倒空,剩下0,同理,可以写出其他5种状态的表达式。
#include <iostream> #include <queue> #include <map> using namespace std; int A, B, C; struct Status { int x, y; Status() :x(0), y(0){} Status(int _x, int _y) :x(_x), y(_y){} bool operator<(const Status& b) const { return x == b.x ? y < b.y : x < b.x; } Status AToB()//A瓶倒入B瓶 { Status c; c.x = max(x + y - B, 0);//如果B瓶装不下,A瓶剩x+y-B,否则A瓶空 c.y = min(B, x + y); return c; } Status BToA() { Status c; c.y = max(x + y - A, 0); c.x = min(A, x + y); return c; } Status FillA() { return Status(A, y); } Status FillB() { return Status(x, B); } Status EmptyA() { return Status(0, y); } Status EmptyB() { return Status(x, 0); } }; map<Status, bool> visit; map<Status, string> act; map<Status, Status> pre; queue<Status> q; void print(Status t) { if (act.find(t) != act.end()) { print(pre[t]); cout << act[t] << endl; } } void bfs(int a, int b) { visit.clear(); act.clear(); pre.clear(); Status t(a, b); q.push(t); visit[t] = 1; while (!q.empty()) { t = q.front(); q.pop(); if (t.x == C || t.y == C) { print(t); return; } Status x = t.AToB(); if (visit[x] == 0) { visit[x] = 1; q.push(x); act[x] = "pour A B"; pre[x] = t; } x = t.BToA(); if (visit[x] == 0) { visit[x] = 1; q.push(x); act[x] = "pour B A"; pre[x] = t; } x = t.FillA(); if (visit[x] == 0) { visit[x] = 1; q.push(x); act[x] = "fill A"; pre[x] = t; } x = t.FillB(); if (visit[x] == 0) { visit[x] = 1; q.push(x); act[x] = "fill B"; pre[x] = t; } x = t.EmptyA(); if (visit[x] == 0) { visit[x] = 1; q.push(x); act[x] = "empty A"; pre[x] = t; } x = t.EmptyB(); if (visit[x] == 0) { visit[x] = 1; q.push(x); act[x] = "empty B"; pre[x] = t; } } } int main() { while (cin >> A >> B >> C) { while (!q.empty()) q.pop(); bfs(0, 0); cout << "success" << endl; } return 0; }