题目1:
见https://www.luogu.com.cn/problem/P1443
思路1:
bfs模板题,马每次可以跳8个方位,把当前马在的位置所能跳到的点入队并标记即可,没什么技巧,输出格式需注意!!!
代码1:
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=410;
typedef pair<int,int> PII;
queue<PII> q;
int dx[8]={1,1,-1,-1,2,2,-2,-2},dy[8]={2,-2,2,-2,1,-1,1,-1};
int res[N][N],visit[N][N],temp,n,m;
void bfs(PII p)
{
while(!q.empty())
{
int x=q.front().first,y=q.front().second;
int temp=res[x][y]+1;//当前步数
for(int i=0;i<8;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!visit[nx][ny])
{
q.push({nx,ny});
visit[nx][ny]=1;
res[nx][ny]=temp;
}
}
q.pop();
}
}
int main()
{
int x,y;
cin>>n>>m>>x>>y;
visit[x][y]=1;
memset(res,-1,sizeof(res));
res[x][y]=0;
q.push({x,y});
bfs(q.front());
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
printf("%-5d", res[i][j]);
cout<<endl;
}
return 0;
}
题目2:
见https://www.luogu.com.cn/problem/P1451
思路2:
最简单的求连通块的问题,依次枚举每个点,如果该点是数字1-9且没有被访问过,则对该点进行bfs,bfs中搜索到的所有点均和他连通
代码2:
#include<iostream>
#include<queue>
using namespace std;
const int N=110;
int n,m,res,g[N][N],visit[N][N];
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
typedef pair<int,int>PII;
queue<PII> q;
void bfs()
{
res++;
while(!q.empty())
{
int x=q.front().first,y=q.front().second;
visit[x][y]=1;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(!visit[nx][ny]&&g[nx][ny])
q.push({nx,ny});
}
q.pop();
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char c;
cin>>c;
if(c!='0')
g[i][j]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(!visit[i][j]&&g[i][j])
{
q.push({i,j});
bfs();
}
}
cout<<res<<endl;
return 0;
}
题目3:
见https://www.luogu.com.cn/problem/P1141
思路3:
当时想都没想就直接bfs爆搜,然后tle3个点,后来看了大佬的题解发现这题不能爆搜,爆搜的话那三个点必然tle。大佬的方法是用连通图的想法来防止tle,每次查询一个点的可达块数时,先判断该点是否已经在搜过的连通图当中,如果在就直接输出答案,如果不在则进行搜索。
代码3:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1010;
const int M=100010;
int n,m,g[N][N],visit[N][N],res,ans[M],an;
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
typedef pair<int,int> PII;
queue<PII> q;
void bfs(int k)
{
while(!q.empty())
{
PII t=q.front();
int x=t.first,y=t.second;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&!visit[nx][ny]&&g[x][y]^g[nx][ny]==1)
{
visit[nx][ny]=k;
ans[k]++;
q.push({nx,ny});
}
}
q.pop();
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
char str[N];
scanf("%s",str+1);
int len=strlen(str+1);
for(int j=1;j<=len;j++)
if(str[j]=='0')
g[i][j]=0;
else
g[i][j]=1;
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(visit[x][y])
res=ans[visit[x][y]];
else
{
visit[x][y]=++an;
ans[an]++;
q.push({x,y});
bfs(an);
res=ans[an];
}
cout<<res<<endl;
}
return 0;
}
题目4:
见https://www.luogu.com.cn/problem/P1331
思路4:
该题也是判断连通块,只是连通块必须为方形.然后就有大佬把情况枚举出来了,见https://pengqwq.blog.luogu.org/solution-p1331
学着大佬的方法,可是还是有一个点tle…
代码4:
#include<iostream>
#include<queue>
using namespace std;
const int N=1010;
int r,c,res,g[N][N],visit[N][N],flag=1;
typedef pair<int,int> PII;
queue<PII> q;
int dx[2]={0,1},dy[2]={1,0};//学着大佬的剪枝优化可是还是tle一个点
bool judge(int i,int j)
{
if (g[i][j]==1)
{
if (g[i+1][j-1]==1)
{
if (g[i+1][j]==0 || g[i][j-1]==0)
{
return 1;
}
}
if (g[i+1][j+1]==1)
{
if (g[i+1][j]==0 || g[i][j+1]==0)
{
return 1;
}
}
if (g[i-1][j-1]==1)
{
if (g[i][j-1]==0 || g[i-1][j]==0)
{
return 1;
}
}
if (g[i-1][j+1]==1)
{
if (g[i-1][j]==0 || g[i][j+1]==0)
{
return 1;
}
}
}
return 0;
}
void bfs()
{
res++;
while(!q.empty())
{
int x=q.front().first,y=q.front().second;
visit[x][y]=1;
for(int i=0;i<2;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=r&&ny>=1&&ny<=c&&!visit[nx][ny]&&g[nx][ny])
if(judge(nx,ny))
{
flag=0;
return;
}
else
q.push({nx,ny});
}
q.pop();
}
}
int main()
{
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
char c;
cin>>c;
if(c=='.')
g[i][j]=0;
else if(c=='#')
g[i][j]=1;
}
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
if(!visit[i][j]&&g[i][j])
{
q.push({i,j});
bfs();
if(!flag)
break;
}
if(!flag)
break;
}
if(flag)
printf("There are %d ships.\n",res);
else
cout<<"Bad placement."<<endl;
}