7.5
依然是继续kuangbin的搜索套题,bfs中用vis数组来去重是一个很重要的步骤啊啊啊;
Kuangbin:简单搜索
A. Dungeon Master(POJ_2251)
传送门
三维bfs,开个三维数组Map,方向选择上多一个上下就行;
#include <iostream>
#include <cstring>
#include <queue>
#define ll long long
#define mms(a, b) memset(a, b, sizeof(a))
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 30 + 10;
int l, r, c;
int Map[maxn][maxn][maxn];
int dir[6][3] = { {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1} };
struct crd {
int x, y, z;
}st, ed;
bool jdg(int x, int y, int z) {
return x > 0 && y > 0 && z > 0 && x <= r && y <= c && z <= l;
}
void bfs() {
queue<crd> q;
q.push(st);
while (!q.empty()) {
crd now = q.front();
q.pop();
for (int i = 0; i < 6; i++) {
int x = now.x + dir[i][0];
int y = now.y + dir[i][1];
int z = now.z + dir[i][2];
if (jdg(x, y, z) && !Map[x][y][z]) {
Map[x][y][z] = Map[now.x][now.y][now.z] + 1;
crd temp = { x, y, z };
q.push(temp);
}
}
}
}
void solve() {
mms(Map, 0);
for (int k = 1; k <= l; k++) {
for (int i = 1; i <= r; i++) {
for (int j = 1; j <= c; j++) {
char c;
cin >> c;
if (c == 'S') {
crd temp = { i, j, k };
st = temp;
}
else if (c == 'E') {
crd temp = { i, j, k };
ed = temp;
}
else if (c == '#') {
Map[i][j][k] = -1;
}
}
}
}
bfs();
if (Map[ed.x][ed.y][ed.z]) {
cout << "Escaped in " << Map[ed.x][ed.y][ed.z] << " minute(s)." << '\n';
}
else {
cout << "Trapped!" << '\n';
}
}
signed main() {
std::ios::sync_with_stdio(false);
/* cin.tie(nullptr);
cout.tie(nullptr); */
while (cin >> l >> r >> c) {
if (l == 0 && r == 0 && c == 0)
break;
solve();
}
return 0;
}
B. Catch That Cow(POJ_3278)
传送门
简单bfs,因为边界判断上x >= 0
少写了一个等号导致疯狂wawawa;
#include <iostream>
#include <cstring>
#include <queue>
#define ll long long
#define mms(a, b) memset(a, b, sizeof(a))
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 1;
int n, k;
int Map[maxn], vis[maxn];
int dir[3] = {1, -1, 2};
void bfs() {
vis[n] = 1;
queue<int> q;
q.push(n);
while(!q.empty()) {
int temp = q.front();
q.pop();
for (int i = 0; i < 3; i++) {
int x;
if(i == 2) {
x = temp * 2;
}
else {
x = temp + dir[i];
}
if(x >= 0 && x < maxn && !vis[x]) {
vis[x] = 1;
Map[x] = Map[temp] + 1;
q.push(x);
}
}
}
}
void solve() {
mms(Map, 0);
mms(vis, 0);
bfs();
cout << Map[k] << '\n';
}
signed main() {
std::ios::sync_with_stdio(false);
/* cin.tie(nullptr);
cout.tie(nullptr); */
while (cin >> n >> k) {
solve();
}
return 0;
}
C. 迷宫问题(POJ_3984)
传送门
比较有意思,记忆化bfs,用一个数组来存bfs过的Node,然后在结构体里面加一个pre用来指向当前Node的前一个Node(有点链表内味儿了),最后用dfs遍历数组递归输出路径就行;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define ll long long
#define mms(a, b) memset(a, b, sizeof(a))
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 1;
int Map[6][6];
int dir[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
bool vis[6][6];
struct crd {
int pre, x, y;
}st;
vector<crd> ans;
int bfs() {
int idx = 0;
ans.push_back(st);
vis[1][1] = true;
while (true) {
for (int i = 0; i < 4; i++) {
int x = ans[idx].x + dir[i][0];
int y = ans[idx].y + dir[i][1];
if (x >= 0 && x < 5 && y >= 0 && y < 5 && !Map[x][y] && !vis[x][y]) {
crd t = { idx, x, y };
ans.push_back(t);
vis[x][y] = true;
if (x == 4 && y == 4) {
return idx;
}
}
}
idx++;
}
}
void print(int temp) {
if (ans[temp].pre == -1) {
printf("(%d, %d)\n", ans[temp].x, ans[temp].y);
return;
}
print(ans[temp].pre);
printf("(%d, %d)\n", ans[temp].x, ans[temp].y);
}
void solve() {
mms(vis, false);
for (int i = 0; i <= 4; i++) {
for (int j = 0; j <= 4; j++) {
cin >> Map[i][j];
}
}
crd t = { -1, 0, 0 };
st = t;
print(bfs());
printf("(4, 4)\n");
}
signed main() {
std::ios::sync_with_stdio(false);
/* cin.tie(nullptr);
cout.tie(nullptr); */
solve();
return 0;
}
D. Oil Deposits(HDU_1241)
传送门
dfs,跟《挑程》上面的水洼那一题一样的,dfs起点是遍历到的@,然后把每一块儿@都变成*,每执行一次dfs就++ans,最后输出ans就行;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define ll long long
#define mms(a, b) memset(a, b, sizeof(a))
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 1;
int Map[6][6];
int dir[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
bool vis[6][6];
struct crd {
int pre, x, y;
}st;
vector<crd> ans;
int bfs() {
int idx = 0;
ans.push_back(st);
vis[1][1] = true;
while (true) {
for (int i = 0; i < 4; i++) {
int x = ans[idx].x + dir[i][0];
int y = ans[idx].y + dir[i][1];
if (x >= 0 && x < 5 && y >= 0 && y < 5 && !Map[x][y] && !vis[x][y]) {
crd t = { idx, x, y };
ans.push_back(t);
vis[x][y] = true;
if (x == 4 && y == 4) {
return idx;
}
}
}
idx++;
}
}
void print(int temp) {
if (ans[temp].pre == -1) {
printf("(%d, %d)\n", ans[temp].x, ans[temp].y);
return;
}
print(ans[temp].pre);
printf("(%d, %d)\n", ans[temp].x, ans[temp].y);
}
void solve() {
mms(vis, false);
for (int i = 0; i <= 4; i++) {
for (int j = 0; j <= 4; j++) {
cin >> Map[i][j];
}
}
crd t = { -1, 0, 0 };
st = t;
print(bfs());
printf("(4, 4)\n");
}
signed main() {
std::ios::sync_with_stdio(false);
/* cin.tie(nullptr);
cout.tie(nullptr); */
solve();
return 0;
}
E. Prime Path(POJ_3126)
传送门
埃氏筛 + bfs,把个十百千位分别都枚举一遍,一开始枚举的时候我还纠结在加加减减造成进位退位咋办,后来看了下别人的写法发现根本不用去加加减减,直接每一位都从0~9枚举就行了;
至于如何按位进行,有个小技巧,利用int型舍弃小数的特性来枚举,以十位为例子:
int num = 1234;
//若想枚举1204 ~ 1294
for(int i = 0; i <= 9; ++i) {
int tmp = num % 10 /*将个位提出来*/ + (num / 100 * 100) /*括号内为1330*/ + i * 10
}
以此可以类推除百位、千位的枚举方法,需注意千位首位不能为0;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define ll long long
#define mms(a, b) memset(a, b, sizeof(a))
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e4 + 5;
int a, b;
bool isPrm[maxn];
int cnt[maxn];
bool vis[maxn];
void sieve() {
mms(isPrm, true);
isPrm[0] = isPrm[1] = false;
for (int i = 2; i * i < maxn; i++) {
if(isPrm[i]) {
for (int j = i * i; j < maxn; j += i)
isPrm[j] = false;
}
}
}
void bfs() {
queue<int> q;
vis[a] = true;
q.push(a);
while(!q.empty()) {
int num = q.front();
q.pop();
int temp;
for (int i = 0; i <= 9; i++) {
//个位
temp = num / 10 * 10 + i;
if(isPrm[temp] && !vis[temp]) {
vis[temp] = true;
cnt[temp] = cnt[num] + 1;
q.push(temp);
}
//十位
temp = num % 10 + num / 100 * 100 + i * 10;
if(isPrm[temp] && !vis[temp]) {
vis[temp] = true;
cnt[temp] = cnt[num] + 1;
q.push(temp);
}
//百位
temp = num % 100 + num / 1000 * 1000 + i * 100;
if(isPrm[temp] && !vis[temp]) {
vis[temp] = true;
cnt[temp] = cnt[num] + 1;
q.push(temp);
}
//千位
if(i != 0) {
temp = num % 1000 + i * 1000;
if(isPrm[temp] && !vis[temp]) {
vis[temp] = true;
cnt[temp] = cnt[num] + 1;
q.push(temp);
}
}
}
}
}
void solve() {
mms(cnt, 0);
mms(vis, false);
bfs();
cout << cnt[b] << '\n';
}
signed main() {
std::ios::sync_with_stdio(false);
/* cin.tie(nullptr);
cout.tie(nullptr); */
sieve();
int t;
cin >> t;
while(t--) {
cin >> a >> b;
solve();
}
return 0;
}