Educational Codeforces Round 1(D. Igor In the Museum) (BFS+离线访问)

时间:2023-09-02 20:16:26

题目链接:http://codeforces.com/problemset/problem/598/D

题意是 给你一张行为n宽为m的图 k个询问点 ,求每个寻问点所在的封闭的一个上下左右连接的块所能看到的壁画有多少(大概这样吧)。

我的做法是bfs(dfs也可以)这个为'.'的点,要是遇到上下左右其中有'*'的话就加起来。要是每次询问然后bfs一下肯定超时,所以我用一个ans[1005][1005]记录每个点的值,ok[1005][1005]数组判断是否访问过,初始化为false。然后开始遍历一次,遇到'*'的ans则为0,遇到'.' 且 ok[i][j] = false的就bfs周围相连的'.',算出答案然后再逐个赋值给一个房间的ans[i][j],都标记经过 即ok[i][j] = true ...。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue> using namespace std;
char map[MAXN][MAXN];
bool ok[MAXN][MAXN];
int ans[MAXN][MAXN];
int n , m , res , tx[] = {- , , , } , ty[] = { , , , -};
struct data {
int x , y;
}; void init() {
memset(ok , false , sizeof(ok));
} bool judge(int x , int y) { //判断点是否是'.' 且未经过
if(x < n && y < m && x >= && y >= && map[x][y] != '*' && !ok[x][y]) {
return true;
}
return false;
} bool judge2(int x , int y) { //判断点是否是'*'
if(x < n && y < m && x >= && y >= && map[x][y] == '*') {
return true;
}
return false;
} int get(int x , int y) { //壁画的相加
int num = ;
for(int i = ; i < ; i++) {
if(judge2(x + tx[i] , y + ty[i])) {
num++;
}
}
return num;
} void bfs(int x , int y) {
vector<data > v; //用来存相连的'.'
queue <data> Q;
data a;
a.x = x , a.y = y;
Q.push(a);
while(!Q.empty()) {
data temp = Q.front();
v.push_back(temp);
Q.pop();
if(map[temp.x][temp.y] == '.') {
res += get(temp.x , temp.y);
ok[temp.x][temp.y] = true;
}
for(int i = ; i < ; i++) {
a.x = temp.x + tx[i] , a.y = temp.y + ty[i];
if(judge(a.x , a.y)) {
Q.push(a);
ok[a.x][a.y] = true;
}
}
}
for(int i = ; i < v.size() ; i++) {
ans[v[i].x][v[i].y] = res;
}
v.clear(); //清空
} int main()
{
int q , sx , sy;
ios::sync_with_stdio(false);
while(cin >> n >> m >> q) {
memset(ans , , sizeof(ans));
for(int i = ; i < n ; i++)
cin >> map[i];
init();
for(int i = ; i < n ; i++) {
for(int j = ; j < m ; j++) {
res = ;
if(!ok[i][j] && map[i][j] == '.') {
bfs(i , j);
}
}
}
while(q--) {
cin >> sx >> sy;
cout << ans[sx - ][sy - ] << endl;
}
}
}