1、白与黑(林大OJ 784)
解决方案:直接深度优先搜索
Description
有一间长方形的房子,地上铺了白色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
Input
包括多个数据集合。每个数据集合的第一行是两个整数W 和H,分别表示x 方向 和y 方向瓷砖的数量。W 和H 都不超过20。在接下来的H 行中,每行包括W 个字符。 每个字符表示一块瓷砖的颜色,规则如下: 1)‘.’:黑色的瓷砖; 2)‘#’:白色的瓷砖; 3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。 当在一行中读入的是两个零时,表示输入结束。
Output
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。
Sample Input
6 9 ....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 0 0
Sample Output
45
代码如下:
#include<bits/stdc++.h>
using namespace std;
int c,r;
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
int ans;
const int N=20+5;
char Map[N][N];
int vis[N][N];
//.黑瓷砖
// #白瓷砖
//@ 目前位置
void dfs(int i,int j)//i为行数,j为列数
{
Map[i][j]='#';
ans++;
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x>=1 && x<=r && y>=1 && y<=c && Map[x][y]=='.')
{
dfs(x,y);
}
}
}
int main()
{
while(cin>>c>>r)
{
if(c==0 && r==0)break;
int idx_i,idx_j;//记录初始位置
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
cin>>Map[i][j];
if(Map[i][j]=='@')
{
idx_i=i;
idx_j=j;
}
}
ans=0;
dfs(idx_i,idx_j);
cout<<ans<<endl;
memset(Map,0,sizeof(Map));
}
return 0;
}
2、迷宫寻路(林大OJ 558)
Description
AC小公主很喜欢设计迷宫,她设计的迷宫只有两个口,一个入口,一个出口。但小公主有时候很调皮,她会让挑战者走不出迷宫。现在给你AC小公主的迷宫请你判断挑战者能否成功从出口走出迷宫,迷宫包证边界为障碍物,只有两个不同的入口。 “#”代表障碍物,“*”代表可走的路。
Input
输入有多组,每组输入两个正整数n,m( 2 < n < m < 1000)。 接下来n行,每行有m个字符。
Output
每组测试实例,若挑战者能走出迷宫输出”YES”,否则输出“NO”。
Sample Input
3 3 #*# #*# #*# 3 3 #*# ### #*#
Sample Output
YES NO
确定出入口开始搜索
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,m;
int sidx,sidy;
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
const int N=1000+5;
char a[N][N];
bool flag;
void dfs(int x,int y)
{
if( (x==n || y==m || x==1 || y==1) && a[x][y]=='*')
{
flag=true;
}
a[x][y]='#';
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1 && nx<=n && ny>=1 && ny<=m && a[nx][ny]=='*')
{
dfs(nx,ny);
}
}
}
int main()
{
while(cin>>n>>m)
{
//随机挑选起点为sidx,sidy
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
for(int i=1;i<=m;i++)
{
if(a[n][i]=='*')
{
sidx=n;sidy=i;
}
if(a[1][i]=='*')
{
sidx=1;sidy=i;
}
}
for(int j=1;j<=n;j++)
{
if(a[j][1]=='*')
{
sidx=j;sidy=1;
}
if(a[j][m]=='*')
{
sidx=j;sidy=m;
}
}
a[sidx][sidy]='#';
flag=false;
dfs(sidx,sidy);
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
3、猴群(林大OJ 1696)
Description
给你一个数字矩阵,其中数字由0-9构成,0代表树木,1-9代表猴子;凡是有0和边缘围起来的区域是猴群。请你计算猴群的数目?
Input
第1行为n和 m,代表行和列数,(1<=n,m<=100)
Output
输出猴群的数目!
Sample Input
4 10 0234500067 1034560500 2045600671 0000000089
Sample Output
4
遇到非零的,直接变成0,然后深度优先搜索周围全变成0,数量+1
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=101;
char g[N][N];
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
int cnt;
int n,m;//行列
//把当前坐标四周不是0的全部变成0
void dfs(int x,int y)
{
g[x][y]='0';
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1 && nx<=n && ny>=1 && ny<=m && g[nx][ny]!='0')
{
dfs(nx,ny);
}
}
}
int main()
{
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>g[i][j];
}
cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(g[i][j]!='0')
{
cnt++;
dfs(i,j);
}
}
cout<<cnt<<endl;
}
return 0;
}
--------------------分割线-----------------
到目前为止一切正常,到下面位置第四题的时候迎接我的是无尽的TLE
在经过几次TLE后,终于发现这题不能用普通的深度优先搜索
以下是最终的solution
4、01迷宫(林大OJ 1702)
应该考虑用连通块来减少时间复杂度
Description
有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。 你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。
Input
第1行为两个正整数n,m. 下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。 接下来m行,每行2个用空格分隔的正整数i,j,对应了迷宫中第i行第j列的一个格子,询问从这一格开始能移动到多少格。
Output
m行,对于每个询问输出相应答案。
Sample Input
2 2 01 10 1 1 2 2
Sample Output
4 4
Hint
n<=1000,m<=100000
Source
洛谷
记忆化搜索+连通块解决问题
直接处理好图中每个点,明确他们属于哪个连通块,并且每个连通块的面积我们可以通过深度优先搜索求出来,存到ans里,接下来面对询问直接从ans输出答案
代码如下:
//我们发现每个连通块中能到达的点是一样的
#include<bits/stdc++.h>
using namespace std;
const int N=1001;
const int M=1e6+10;
int n,m;
int q[M];
char g[N][N];
int vis[N][N];
int cnt=0,flag[N][N],ans[N*N];
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
vector<int>r;
void dfs(int x,int y)
{
vis[x][y]=1;
flag[x][y]=cnt;//标记x,y这个点属于第cnt个连通块
ans[flag[x][y]]++;//第cnt个连通块的面积+1
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1 && nx<=n && ny>=1 && ny<=n && !vis[nx][ny] && g[nx][ny]!=g[x][y])
{
dfs(nx,ny);
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>g[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(!vis[i][j])//如果没有访问过那就是其他的连通块
{
cnt++;
dfs(i,j);
}
}
while(m--)
{
int o,p;
cin>>o>>p;
printf("%d\n",ans[flag[o][p]]);
}
return 0;
}