题目描述
有一个仅由数字 0 0 0与 1 1 1组成的 n × n n \times n n×n格迷宫。若你位于一格 0 0 0上,那么你可以移动到相邻 4 4 4格中的某一格 1 1 1上,同样若你位于一格 1 1 1上,那么你可以移动到相邻 4 4 4格中的某一格 0 0 0上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
输入格式
第 1 1 1行为两个正整数 n , m n,m n,m。
下面 n n n行,每行 n n n个字符,字符只可能是 0 0 0或者 1 1 1,字符之间没有空格。
接下来 m m m行,每行 2 2 2个用空格分隔的正整数 i , j i,j i,j,对应了迷宫中第 i i i行第 j j j列的一个格子,询问从这一格开始能移动到多少格。
输出格式
m m m行,对于每个询问输出相应答案。
样例输入 #1
2 2
01
10
1 1
2 2
样例输出 #1
4
4
提示
所有格子互相可达。
对于 20 % 20\% 20%的数据, n ≤ 10 n≤10 n≤10;
对于 40 % 40\% 40%的数据, n ≤ 50 n≤50 n≤50;
对于 50 % 50\% 50%的数据, m ≤ 5 m≤5 m≤5;
对于 60 % 60\% 60%的数据, n ≤ 100 , m ≤ 100 n≤100,m≤100 n≤100,m≤100;
对于 100 % 100\% 100%的数据, n ≤ 1000 , m ≤ 100000 n≤1000,m≤100000 n≤1000,m≤100000。
记忆化搜索~
#include
using namespace std;
const int N = 1e3 + 10;
#include //memset !
char g[N][N];
bool st[N][N];
int n, q;
int cnt;
//最长路径
void dfs(int x, int y)
{
//visited
if (st[x][y])
return;
//否则
++cnt;
st[x][y] = true;
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && (g[x][y] == '0' && g[a][b] == '1' || g[x][y] == '1' && g[a][b] == '0'))
dfs(a, b);
}
}
int main()
{
scanf("%d%d", &n, &q);
getchar(); //吞\n
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
while (q--)
{
//init
memset(st, 0, sizeof st);
cnt = 0;
int x, y;
scanf("%d%d", &x, &y);
dfs(x, y);
printf("%d\n", cnt);
}
return 0;
}
由于在搜索某条路径时,包含了很多点,则将这些点均赋值为最终路径长度,避免重复搜索
#include
using namespace std;
const int N = 1e3 + 10;
#include //memset !
#include //记录路径
typedef pair<int, int> PII;
set<PII>SP;
char g[N][N];
bool st[N][N];
int d[N][N];
int n, q;
int cnt;
//最长路径
void dfs(int x, int y)
{
//visited
if (st[x][y])
return;
//否则
++cnt;
st[x][y] = true;
SP.insert({x,y}); //记录路径
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && (g[x][y] == '0' && g[a][b] == '1' || g[x][y] == '1' && g[a][b] == '0'))
dfs(a, b);
}
}
int main()
{
scanf("%d%d", &n, &q);
getchar(); //吞\n
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
while (q--)
{
int x, y;
scanf("%d%d", &x, &y);
if (d[x][y]) {
printf("%d\n", d[x][y]);
}
else
{
//init
memset(st, 0, sizeof st);
SP.clear(); //清空路径记录
cnt = 0;
dfs(x, y);
for (auto x : SP)
{
int a = x.first, b = x.second;
d[a][b] = cnt;
}
printf("%d\n", cnt);
}
}
return 0;
}
可以将不同的连通块染成不同的颜色,即做不同的标记,给每个标记赋上不同的值即可
//dfs+染色
#include
using namespace std;
#include
const int N = 1e3 + 10;
const int M = 1e5 + 10;
int cr[M]; //记录每个颜色所对应的答案
char g[N][N]; //迷宫
int d[N][N]; //标记连通块 并 染色
int n, m;
void dfs(int x, int y, int fg, int col)
{
//base case 已经写到 for循环中
d[x][y] = col; //标记为 col
cr[col]++; //标记为col的路径长度+1
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && d[a][b] == -1 && g[a][b]-'0'==!fg)
dfs(a, b, !fg, col);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
memset(d, -1, sizeof d);
for (int i = 0; i < m; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
if (d[x][y] == -1)//未遍历
dfs(x, y, g[x][y] - '0', i);
printf("%d\n", cr[d[x][y]]);
}
return 0;
}
#include
using namespace std;
#include
#include //memset
const int N = 1e3 + 10, M = 1e5 + 10;
typedef pair<int, int> PII;
queue<PII> q;
char g[N][N]; //迷宫
int d[N][N]; //搜索
int col[M];
int n, m;
int k; //连通图标记
void bfs(int x, int y)
{
//init
d[x][y] = k;
col[k]++;
q.push({ x,y });
int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 };
while (q.size())
{
//取队头
auto t = q.front();
q.pop();
for (int i = 0; i < 4; ++i)
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= n && d[a][b] == -1 && (g[t.first][t.second] ^ 48) + (g[a][b] ^ 48) == 1)
{
d[a][b] = k;
col[k]++;
q.push({ a,b });
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%s", g[i] + 1);
//init dist
memset(d, -1, sizeof d);
for (int i = 0; i < m; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
if (d[x][y] == -1)
{
//new 连通块
k++;
bfs(x, y);
}
printf("%d\n", col[d[x][y]]);
}
return 0;
}
dfs的优势在于所占内存较少,速度上比bfs慢些~
bfs 、 dfs 、染色~
2022.8.27 整理
欢迎交流、讨论、指正~
不正确、不理解之处欢迎评论留言~