题目链接:
题意:
这个题目的意思是:给定一个h*w的方格内,只有' . ' 和 ' # ' 两个符号,
请问有多少条路径是 ' . ' ------> ' # ' ,其中路径中必须是 ' . ' 和 ’ # ‘ 相间。
小结:
这个题真的不会做,我当时就懵逼了,啥都不知道,然后看了网友的做法,发现原来就是找联通块,只要找到联通块就行了,这个答案就是:
ans=每个联通块内 ' . ' 的个数 × ’ # ‘ 的个数
题解:
这个题提供了三种做法,第一种是DFS,就是抄袭网友的做法,第二种和第三种是看胜营哥的博客得知的。
其实如果我知道答案是求一个联通块,其实就很简单了,我就是题做得太少了。
第一种方法:是用到了vector < pair <int,int> >。其中,用到更多的是for( auto )这个结构来简化代码量
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e2+10;
char a[N][N];
typedef pair<int,int> P;
vector<P> V[N][N];
int n,m;
int dir[4][2]={
{-1,0},
{0,-1},{0,1},
{1,0}
};
bool check(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
int cnt[2];
bool vis[N][N];
void dfs(int x,int y){
vis[x][y]=true;
if(a[x][y]=='#'){
cnt[0]++;
}else{
cnt[1]++;
}
for(auto v: V[x][y] ){
if(!vis[v.first][v.second]){
dfs(v.first,v.second);
}
}
}
int main()
{
int h,w;
scanf("%d%d",&h,&w);
n=h,m=w;
for(int i=1;i<=h;i++){
scanf("%s",a[i]+1);
}
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
for(int k=0;k<4;k++){
int tx=i+dir[k][0];
int ty=j+dir[k][1];
if(check(tx,ty)&&a[i][j]!=a[tx][ty]){
V[i][j].push_back(make_pair(tx,ty));
}
}
}
}
ll ans=0;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
memset(cnt,0,sizeof(cnt));
if(!vis[i][j]){
dfs(i,j);
ans+=1LL*cnt[0]*cnt[1];
}
}
}
printf("%lld\n",ans);
return 0;
}
第二种方法:哈希+联通块:(胜营大佬提供的)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e2+10;
char a[N][N];
ll h,w,vis[N*N],Cnt[N*N],Dot[N*N],pre[N*N];
int dir[4][2]={
{-1,0},
{0,-1},{0,1},
{1,0}
};
int Hash(int x,int y){
return (x-1)*w+y;
}
int Find(int x){
return x==pre[x]?x:Find(pre[x]);
}
void Merge(int x,int y){
int fx=Find(x);
int fy=Find(y);
if(fx!=fy){
pre[fy]=fx;
Cnt[fx]+=Cnt[fy];
Dot[fx]+=Dot[fy];
}
}
bool check(int x,int y){
return (x<1||y<1||x>h||y>w)?false:true;
}
int main()
{
scanf("%lld%lld",&h,&w);
for(int i=1;i<=h*w+10;i++){
pre[i]=i;
}
for(int i=1;i<=h;i++){
scanf("%s",a[i]+1);
}
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
Cnt[Hash(i,j)]++;
if(a[i][j]=='.'){
Dot[Hash(i,j)]++;
}
}
}
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
for(int k=0;k<4;k++){
int tx=i+dir[k][0];
int ty=j+dir[k][1];
if(check(tx,ty)&&a[i][j]!=a[tx][ty]){
int Fx=Hash(i,j);
int Fy=Hash(tx,ty);
Merge(Fx,Fy);
}
}
}
}
ll ans=0;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
int t=Hash(i,j);
int Father=Find(t);
if(!vis[Father]){
ans=ans+(Cnt[Father]-Dot[Father])*Dot[Father];
vis[Father]=1;
}
}
}
printf("%lld\n",ans);
return 0;
}
第三种方法:其实求的东西都一样,但是就是写法上有丝毫差别。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e2+15;
int h,w,vis[N][N];
char a[N][N];
bool check(int x,int y){
return (x<1||y<1||x>h||y>w)?false:true;
}
int dir[4][2]={
{-1,0},
{0,-1},{0,1},
{1,0}
};
int main()
{
scanf("%d%d",&h,&w);
for(int i=1;i<=h;i++){
scanf("%s",a[i]+1);
}
ll ans=0;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
if(!vis[i][j]){
queue < pair<int,int> > Q;
Q.push(make_pair(i,j));
ll Dot,Well;
Dot=Well=0;
while(!Q.empty()){
pair<int,int> cur=Q.front();
Q.pop();
int x=cur.first;
int y=cur.second;
if(vis[x][y]==1)
continue;
//printf("[ %d,%d ]\n",x,y);
vis[x][y]=1;
a[x][y]=='.'?Dot++:Well++;
for(int k=0;k<4;k++){
int tx=x+dir[k][0];
int ty=y+dir[k][1];
if(!vis[tx][ty]&&check(tx,ty)&&a[x][y]!=a[tx][ty]){
Q.push(make_pair(tx,ty));
}
}
}
ans+=Dot*Well;
//printf("(%d,%d) = %lld %lld %lld\n",i,j,Dot,Well,Dot*Well);
}
}
}
printf("%lld\n",ans);
return 0;
}