洛谷P1141 传送门
这个题是昨天下午开始写的,昨天我一直以为是求最远路径,然后交了以后不是wa就是T,今天早上学长告诉我是求最大连通块。。。
其实除了审题有问题以外,还有一个问题,就是这道题的询问次数可能高达十万次,就算是用时间复杂度较低的bfs也肯定会T,为什么我这么肯定呢?因为:
学长是用两个dfs写的,第一个dfs用来标记所有连通块,第二个dfs用来记录当前连通块中每个格子。 什么意思呢?让我们来看样例:
2 2
01
10
1 1
2 2
样例中有两次询问,第一次是1,1第二次是2,2。但是我们可以发现,第一次询问之后可以发现整个图形都是连通的,即这四个位置都是同属一个连通块的
,那么我们第一次询问之后,完全可以把这四个位置的答案都记录下来
,这样一来,下一次询问这一连通块的任意一个格子都不需要再进行搜索,直接输出答案即可
代码如下:
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#include <map>
#include <math.h>
#include <set>
#include <vector>
#include <stack>
#include <sstream>
#define ll long long
using namespace std;
int mov[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int vis[1005][1005];
int answ[1005][1005];//记录对应位置的答案
char mp[1005][1005];
int n, m;
int ans;
int ct;
struct node
{
char now;
int x, y;
} fst, sec;
queue<node> q;
void bfs()
{
while (!q.empty())
{
ans++;
fst = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int xx = fst.x + mov[i][0];
int yy = fst.y + mov[i][1];
if (xx < 1 || xx > n || yy < 1 || yy > n || mp[fst.x][fst.y] == mp[xx][yy] || vis[xx][yy] == ct)
continue;
vis[xx][yy] = ct;
sec.now = mp[xx][yy];
sec.x = xx;
sec.y = yy;
q.push(sec);
}
}
}
void dfs(int x, int y)
{
answ[x][y] = ans;
for (int i = 0; i < 4; i++)
{
int xx = x + mov[i][0];
int yy = y + mov[i][1];
if (xx < 1 || xx > n || yy < 1 || yy > n || vis[xx][yy] != ct)
continue;
vis[xx][yy] = 0;
dfs(xx, yy);
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> mp[i] + 1;
while (m--)
{
ct++;
ans = 0;
int a, b;
cin >> a >> b;
if (answ[a][b] != 0)
cout << answ[a][b] << endl;
else
{
while (!q.empty())
q.pop();
fst.now = mp[a][b];
fst.x = a;
fst.y = b;
q.push(fst);
vis[a][b] = ct;
bfs();
dfs(a, b);
cout << ans << endl;
}
}
return 0;
}