问题描述

alt

思路

此题可以用DFS遍历每个位置上的数是1的结点,用计数变量cnt来表示每个子节点含有连通分块的数量,然后进行累加,因此每个位置只能遍历一次,在递归回溯的时候,不用恢复现场。

代码部分

  • 方法一:DFS
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int a[40][70],b[40][70];
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
int res=-0x3f3f3f3f;
int dfs(int x,int y)
{
	int cnt=1;
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i],ny=y+dy[i];
		if(nx>=1&&nx<=30&&ny>=1&&ny<=60&&!b[nx][ny]&&a[nx][ny]==1)
		{
			b[nx][ny]=1;
			cnt+=dfs(nx,ny);
//			b[nx][ny]=0;// 没有回溯
		}
	}
	return cnt;
}
int main ()
{
	for(int i=1;i<=30;i++){
		for(int j=1;j<=60;j++){
			cin>>a[i][j];
		} 
	}
	for(int i=1;i<=30;i++){
		for(int j=1;j<=60;j++)
		{
			b[i][j]=1;
			res=max(res,dfs(i,j));
//			b[i][j]=0; //没有回溯
		}
	}
	cout<<res<<endl;
	return 0;
}
  • 方法二:记忆化搜索
#include <bits/stdc++.h>
using namespace std;
int a[35][65],b[35][65],c[35][65];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
int Maxn=-0x3f3f3f3f;
int dfs(int x,int y)
{
	int cnt=1;
	if(c[x][y]!=-1) return cnt+c[x][y];
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i],ny=y+dy[i];
		if(nx>=1&&nx<=5&&ny>=1&&ny<=5&&a[nx][ny]==1&&!b[nx][ny])
		{
			b[nx][ny]=1;
			cnt+=dfs(nx,ny);
		}
	}
	c[x][y]=cnt;
	return c[x][y];
}
int main ()
{
	memset(c,-1,sizeof c);
	for(int i=1;i<=5;i++)
	{
		for(int j=1;j<=5;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=5;i++)
	{
		for(int j=1;j<=5;j++)
		{
			if(a[i][j]==1)
			{
				b[i][j]=1;
				Maxn=max(Maxn,dfs(i,j));
			}
		}
	}
	cout<<Maxn<<endl;
	return 0;
}
  • 方法三:BFS
#include <bits/stdc++.h>
using namespace std;
const int N=1e2+10;
typedef pair<int,int> PII;
queue<PII> q;
int a[N][N],b[N][N];//b[N][N]数组不仅代表是否遍历,且代表到此点要多少步 
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
int n,m;
int bfs(int x,int y)
{
	int cnt=1;// 在主函数中已经判断(x,y)这个点是1,所以cnt的初始值为1
	b[x][y]=1;
	q.push({x,y});
	while(!q.empty())
	{
		auto t=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int nx=t.first+dx[i],ny=t.second+dy[i];
			if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[nx][ny]==1&&!b[nx][ny])
			{
				b[nx][ny]=1;
				q.push({nx,ny});
				cnt++;
			}
		}
	}
	return cnt;
}
int main ()
{
	cin>>n>>m; 
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>a[i][j];
	int res=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(!b[i][j]&&a[i][j]==1) // 每个点只能遍历一次
			{
				res=max(res,bfs(i,j));	
			}
	cout<<res<<endl;
	return 0;
}