题目链接、
给你一张#和.构成的n*n的图,求有多少对<#,.>(<#,.>满足#到.有一条#.#.这样间隔的路(可以走上下左右四个方向))
一开始没读懂题,半蒙半猜得清楚题意后,写了个hash+并查集,没想到异常的顺利,过了
看官方题解好像是bfs
我是这样想的
对于一个点可以和周围四个#连接在一起(#同点也一样),这样构造联通块,
对于一个联通块,里面的每一个#能够到达每一个点,那么一个联通块的对数就是块内#数乘点的个数
这样把二维的点hash成一个数,然后用一般的并查集构造联通块,然后加两个权表示联通块内的总数和#数
就可以了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int dir[4][2] = {
0,1,
-1,0, 1,0,
0,-1
};
int n,m;
ll ans;
char s[405][405];
int p[maxn],cnt[maxn],c_[maxn];
int Hash(int x,int y){
return x*400+y;
}
int Find(int x){
return x == p[x]?x:p[x] = Find(p[x]);
}
void Merge(int x,int y){
x = Find(x),y = Find(y);
if(x!=y){
p[x] = y;
cnt[y] += cnt[x];
c_[y] += c_[x];
}
}
int main(){
for(int i=0;i<maxn;i++)
p[i] = i,cnt[i] = 1;
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>s[i]+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(s[i][j] == '#')
c_[Hash(i,j)] = 1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
int x = i+dir[k][0];
int y = j+dir[k][1];
if(x>0&&x<=n&&y>0&&y<=m && s[i][j]!=s[x][y]){
Merge(Hash(x,y),Hash(i,j));
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int h = Find(Hash(i,j));
if(cnt[h]>1){
ans += 1ll*c_[h]*(cnt[h]-c_[h]);
cnt[h] = -1;
}
}
}
cout<<ans<<endl;
return 0;
}
打完比赛后写的bfs,仍然是求联通块、
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
char s[402][402];
bool vis[402][402];
int dir[4][2]={
0,1,
-1,0, 1,0,
0,-1
};
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,m,c1,c2;
ll ans = 0;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>s[i]+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!vis[i][j] && s[i][j] == '#'){
c1 = c2 = 0;
queue<pair<int,int> > Q;
Q.push(make_pair(i,j));
vis[i][j] = 1;
while(!Q.empty()){
pair<int,int> t = Q.front(),tt;
Q.pop();
if(s[t.first][t.second] == '#')
c1++;
c2++;
for(int k=0;k<4;k++){
tt = make_pair(t.first+dir[k][0],t.second+dir[k][1]);
if(tt.first>0 && tt.first<=n && tt.second>0 && tt.second<=m )
if(!vis[tt.first][tt.second] && s[t.first][t.second]!=s[tt.first][tt.second])
Q.push(tt),vis[tt.first][tt.second] = 1;
}
}
ans += 1ll*c1*(c2-c1);
}
}
}
cout<<ans<<endl;
return 0;
}