前言
BFS模板題
正文
【問題描述】
小明有一塊空地,他將這塊空地劃分爲 n 行 m 列的小塊,每行和每列的長度都爲 1。
小明選了其中的一些小塊空地,種上了草,其他小塊仍然保持是空地。
這些草長得很快,每個月,草都會向外長出一些,如果一個小塊種了草,則它將向自己的上、下、左、右四小塊空地擴展,這四小塊空地都將變爲有草的小塊。
請告訴小明,k 個月後空地上哪些地方有草。
【輸入格式】
輸入的第一行包含兩個整數 n, m。
接下來 n 行,每行包含 m 個字母,表示初始的空地狀態,字母之間沒有空格。如果爲小數點,表示爲空地,如果字母爲 g,表示種了草。
接下來包含一個整數 k。
【輸出格式】
輸出 n 行,每行包含 m 個字母,表示 k 個月後空地的狀態。如果爲小數點,表示爲空地,如果字母爲 g,表示長了草。
【樣例輸入】
4 5
.g…
…
…g…
…
2
【樣例輸出】
gggg.
gggg.
ggggg
.ggg.
【評測用例規模與約定】
對於 30% 的評測用例,2 <= n, m <= 20。
對於 70% 的評測用例,2 <= n, m <= 100。
對於所有評測用例,2 <= n, m <= 1000,1 <= k <= 1000。
注意:
/*
在做算法題時,使用cin和cout在數據量很大時容易造成超時的情況。此時輸入輸出需要改爲使用scanf和printf。下面的代碼可節省時間,增強cin和cout的效率。
*/
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
思路
典型的BFS模板題,首先讀入整個地圖,將種草的點加入到隊列,同時標記其已被訪問
再從隊列中逐個取出, 若其month小於k,則對其上下左右進行擴張,並將滿足條件的點加入到隊列中去, 標記已被訪問 。最後再遍歷vis標記數組,輸出打印即可
參考題解
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
#include<algorithm>
//標記訪問數組
int vis[1010][1010];
//對應(1,0)(0,1)(-1,0)(0,-1)即右上左下
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
//土地
struct point{
int x;//行
int y;//列
int month;//第幾個月長的
};
using namespace std;
int main(){
int n,m,k;
char ch;
queue<point> q;
//加快cin和cout的效率
ios::sync_with_stdio(0);
cin.tie(0);
cin.tie(0);
cin>>n>>m;
cin.get(ch);//讀取換行符
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin.get(ch);
if(ch=='g'){//初始化的時候該處有草
struct point p={
i,j,0
};
q.push(p);
vis[i][j]=1;//設置該點已被訪問
}
}
cin.get(ch);//讀取換行符
}
cin>>k;
//bfs通用模板
while(!q.empty()){
struct point p=q.front();
int month=p.month;
q.pop();
if(month<k){//若該塊長草的土地的月份小於k,則繼續向外擴展
for(int i=0;i<4;i++){//循環遍歷右上左下四個方向 ,四個新座標
int nx=dx[i]+p.x;
int ny=dy[i]+p.y;
if(0<=nx&&nx<n&&0<=ny&&ny<=m&&vis[nx][ny]==0){//沒有超過邊界且未被訪問
q.push({nx,ny,month+1});//加入隊列
vis[nx][ny]=1;//設置已被訪問
}
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(vis[i][j]==1)cout<<'g';
else cout<<'.';
}
cout<<endl;
}
return 0;
}