一、floodfill
(1)
bfs,dfs均可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N =1010;
int dx[8]={0,-1,-1,-1,0,1,1,1},dy[8]={-1,-1,0,1,1,1,0,-1};
char g[N][N];
int n,m;
bool st[N][N];
int ans;
void bfs()
{
queue<PII> q;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(!st[i][j]&&g[i][j]=='W')
{
ans++;
q.push({i,j});
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<8;i++)
{
int x=t.first+dx[i],y=t.second+dy[i];
if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]=='W')
if(!st[x][y]) st[x][y]=true,q.push({x,y});
}
}
}
else continue;
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>g[i];
bfs();
cout<<ans;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4194842/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(2)
位运算来考虑墙。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N =55;
int n,m;
int g[N][N];
bool st[N][N];
int cnt;
int dx[4] = {0, -1, 0, 1}, dy[4] = {-1, 0, 1, 0};
int bfs(int sx,int sy)
{
queue<PII> q;
int area=0;
q.push({sx,sy});
st[sx][sy]=true;
while(q.size())
{
area++;
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int a=t.first+dx[i],b=t.second+dy[i];
if(a<0||b<0||a>=n||b>=m) continue;
if(st[a][b]) continue;
if(g[t.first][t.second]>>i&1) continue;//这个方向门不开(要和dx dy配合)
q.push({a,b});
st[a][b]=true;
}
}
return area;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>g[i][j];
int area=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(!st[i][j])
{
area=max(area,bfs(i,j));
cnt++;
}
}
cout<<cnt<<endl;
cout<<area<<endl;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4200345/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(3)
每个点bfs一遍,bfs时如果碰到height一样的就加入队列,如果碰到height不一样的则判断正在搜索的是山峰还是山谷。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 1010;
int n;
int h[N][N];
bool st[N][N];
void bfs(int i,int j,bool &hash,bool &hasl)
{
queue<PII> q;
q.push({i,j});
st[i][j]=true;
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=t.x-1;i<=t.x+1;i++)
for(int j=t.y-1;j<=t.y+1;j++)
{
if(i==t.x&&j==t.y) continue;
if(i<0||j<0||i>=n||j>=n) continue;
if(h[i][j]!=h[t.x][t.y])
{
if(h[i][j]>h[t.x][t.y]) hash=true;
else hasl=true;
}
else if(!st[i][j])
{
st[i][j]=true;
q.push({i,j});
}
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>h[i][j];
int peak=0,valley=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(!st[i][j])
{
bool hash=false,hasl=false;
bfs(i,j,hash,hasl);
if(!hash) peak++;
if(!hasl) valley++;
}
}
cout<<peak<<" "<<valley;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4200594/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
二、最短路模型
(1)
边权为1,bfs可找最短路。用pre数组存储某个点的前驱,则可获得最短路线
为方便,反向搜索最短路,然后可从0,0开始直接输出前驱,即为正向最短路
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N =1010,M=N*N;
int n;
int g[N][N];
PII pre[N][N];
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void bfs(int sx,int sy)
{
queue<PII> q;
q.push({sx,sy});
memset(pre,-1,sizeof pre);
pre[sx][sy]={0,0};
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||b<0||a>=n||b>=n) continue;
if(g[a][b]) continue;
if(pre[a][b].x!=-1) continue;//被搜过
q.push({a,b});
pre[a][b]=t;
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>g[i][j];
bfs(n-1,n-1);
PII end(0,0);//构造函数
while(true)
{
cout<<end.x<<" "<<end.y<<endl;
if(end.x==n-1&&end.y==n-1) break;
end=pre[end.x][end.y];
}
return 0;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4202184/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(2)
直接bfs搜,,计算一下跳跃之后坐标的数组即可
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N =155;
int n,m;
char g[N][N];
int dist[N][N];
int bfs()
{
int dx[] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[] = {1, 2, 2, 1, -1, -2, -2, -1};
int sx,sy;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(g[i][j]=='K') sx=i,sy=j;
queue<PII> q;
q.push({sx,sy});
memset(dist,-1,sizeof dist);
dist[sx][sy]=0;
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<8;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||b<0||a>=n||b>=m) continue;
if(g[a][b]=='*') continue;
if(dist[a][b]!=-1) continue;
if(g[a][b]=='H') return dist[t.x][t.y]+1;
dist[a][b]=dist[t.x][t.y]+1;
q.push({a,b});
}
}
}
int main()
{
cin>>m>>n;
for(int i=0;i<n;i++) cin>>g[i];
cout<<bfs()<<endl;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4202245/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(3)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N =100010;
int n,k;
int d[N];
int bfs()
{
memset(d,-1,sizeof d);
d[n]=0;
queue<int> q;
q.push(n);
while(q.size())
{
int t=q.front();
q.pop();
if(t==k) return d[t];
int x=t+1;
if(x<=100000&&d[x]==-1)
{
d[x]=d[t]+1;
q.push(x);
}
x=t-1;
if(x>0&&d[x]==-1)
{
d[x]=d[t]+1;
q.push(x);
}
x=2*t;
if(x<=100000&&x>0&&d[x]==-1)
{
d[x]=d[t]+1;
q.push(x);
}
}
}
int main()
{
cin>>n>>k;
if(n>k)//玄学优化
{
printf("%d",n-k);
return 0;
}
else cout<<bfs()<<endl;
}
三、多源bfs
广度优先遍历的正确性:满足两段性和单调性
即1.在访问完所有的第i层节点后,才会开始搜索第i+1层节点。2.任意时刻,队列中至多有两个层次的结点。若其中一部分节点属于第i层,则另一部分节点属于第i+1层,并且所有第i层节点排在第i+1层节点之前。也就是说广度优先队列中的元素满足单调性和两段性。
本题思路: 求出每个0点到距离自己最近的1点的曼哈顿距离。
可以反向思考用每个1点作为虚拟原点,更新周围的0点的距离。
每个1点的距离显然是0。拓展每个节点时,把新元素加入队尾,可以使得队列中永远只有dist为x,与x+1的元素,并且dist为x的元素一定在dist为x+1的元素前面。即满足单调性和两段性。因此做法是正确的。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N =1010;
char g[N][N];
int n,m;
int dist[N][N];
void bfs()
{
queue<PII> q;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
memset(dist,-1,sizeof dist);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(g[i][j]=='1')
{
q.push({i,j});
dist[i][j]=0;
}
}
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||b<0||a>=n||b>=m) continue;
if(dist[a][b]!=-1) continue;
dist[a][b]=dist[t.x][t.y]+1;
q.push({a,b});//注意这个放在队尾的性质
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>g[i];
bfs();
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++) cout<<dist[i][j]<<" ";
cout<<endl;
}
return 0;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4206207/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
四、最小步数模型
分析:求路径—存前驱 状态抽象为字符串 为方便从标准态反向搜索 要求字典序最小—搜索方案按abc的顺序搜。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<unordered_map>
using namespace std;
char g[2][4];
unordered_map<string,int> dist;
unordered_map<string,pair<char,string>> pre;
void set(string state)//把字符串转化成数组魔板,,方便状态转移
{
for(int i=0;i<4;i++) g[0][i]=state[i];
for(int i=7,j=0;j<4;i--,j++) g[1][j]=state[i];
}
string get()
{
string res;
for (int i = 0; i < 4; i ++ ) res += g[0][i];
for (int i = 3; i >= 0; i -- ) res += g[1][i];
return res;
}
string move0(string state)
{
set(state);
for(int i=0;i<4;i++) swap(g[0][i],g[1][i]);
return get();
}
string move1(string state)
{
set(state);
int v0=g[0][3],v1=g[1][3];
for(int i=3;i>0;i--)
g[0][i]=g[0][i-1],g[1][i]=g[1][i-1];
g[0][0]=v0,g[1][0]=v1;
return get();
}
string move2(string state)
{
set(state);
int v = g[0][1];
g[0][1] = g[1][1];
g[1][1] = g[1][2];
g[1][2] = g[0][2];
g[0][2] = v;
return get();
}
int bfs(string start,string end)
{
if(start==end) return 0;
queue<string> q;
q.push(start);
dist[start]=0;
while(q.size())
{
auto t=q.front();
q.pop();
string m[3];
m[0]=move0(t);
m[1] = move1(t);
m[2] = move2(t);
for(int i=0;i<3;i++)//按abc的顺序搜 就是字典序最小的方案
{
if(!dist.count(m[i]))
{
dist[m[i]]=dist[t]+1;
pre[m[i]]={'A'+i,t};
q.push(m[i]);
if(m[i]==end) return dist[m[i]];
}
}
}
return -1;
}
int main()
{
int x;
string start,end;
for(int i=0;i<8;i++)
{
cin>>x;
end+=char(x+'0');
}
for(int i=1;i<=8;i++) start+=char(i+'0');
int step=bfs(start,end);
cout<<step<<endl;
string res;
while(end != start)
{
res+=pre[end].first;
end=pre[end].second;
}
reverse(res.begin(),res.end());
if(step>0) cout<<res<<endl;
return 0;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4208297/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。