题型一:Flood Fill
计算相连通区域块个数 都是判断是否有无被遍历过的条件下 开始进行搜索条件
池塘计数(相连通区域块的个数)
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
const int M=N*N;
char g[N][N];
PII q[M];
bool st[N][N];
int n,m;
bool bfs(int sx,int sy){
int hh=0,tt=0;
q[0]={sx,sy};
st[sx][sy]=true;
while(hh<=tt){
PII t=q[hh++];
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(st[i][j]==true) continue;
if(i<0||i>=n||j<0||j>=m) continue;
if(g[i][j]=='.') continue;
q[++tt]={i,j};
st[i][j]=true;
}
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>g[i];
}
int cnt=0;
memset(st,false,sizeof st);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]=='W'&&st[i][j]==false){//必须确保此次遍历的W不是已经遍历过的联通块
bfs(i,j);
cnt++;
}
}
}
cout<<cnt<<endl;
return 0;
}
城堡问题(区域块计数+记录最大区域块)
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=55;
const int M=N*N;
int n,m;
int g[N][N];
PII q[M];
bool st[N][N];
int bfs(int sx,int sy){
int dx[]={0,-1,0,1};
int dy[]={-1,0,1,0};
int hh=0,tt=0;
int area=0;
q[0]={sx,sy};
st[sx][sy]=true;
while(hh<=tt){
PII t=q[hh++];
area++;//只要能取出 就面积加1
for(int i=0;i<4;i++){
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=m) continue;
if(st[a][b]) continue;
if(g[a][b]>>i&1) continue;
q[++tt]={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 cnt=0,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;
return 0;
}
题型二:最短路模型
bfs一层一层的遍历 最早到达终点的一定是最短的
dist[a][b]=dist[t.x][t.y]+1;
献给阿尔吉侬的花束
//这种仅仅是判断连通性 是否可以抵达并不可以最短路
//最短路采取dist数组更新 或者dfs
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int>PII;
const int N=210;
const int M=N*N;
int n,m;
char g[N][N];
int dist[N][N];
PII q[M];
int bfs(int sx,int sy){
int hh=0,tt=0;
q[0]={sx,sy};
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
memset(dist,-1,sizeof dist);
dist[sx][sy]=0;
while(hh<=tt){
PII t=q[hh++];
for(int i=0;i<4;i++){
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=m) continue;
if (g[a][b]=='#') continue;
if(dist[a][b]!=-1) continue;
if(g[a][b]=='E') return dist[t.x][t.y]+1;
dist[a][b]=dist[t.x][t.y]+1;
q[++tt]={a,b};
}
}
return -1;
}
int main(){
int T;
cin>>T;
while(T--){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>g[i];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]=='S'){
if(bfs(i,j)!=-1){
cout<<bfs(i,j)<<endl;
}else{
cout<<"oop!"<<endl;
}
}
}
}
}
return 0;
}
武士风度的牛
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=155,M=N*N;
int n,m;
char g[N][N];
PII q[M];
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<m;j++){
if(g[i][j]=='K'){
sx=i,sy=j;
}
}
}
int hh=0,tt=0;
q[0]={sx,sy};
memset(dist,-1,sizeof dist);
dist[sx][sy]=0;
while(hh<=tt){
auto t=q[hh++];
for(int i=0;i<8;i++){
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=m) continue;
if(g[a][b]=='*') continue;
if(dist[a][b]!=-1) continue;//是否被遍历过 如果不为-1 就代表已经放入队列中
if(g[a][b]=='H') return dist[t.x][t.y]+1;
dist[a][b]=dist[t.x][t.y]+1;
q[++tt]={a,b};
}
}
return -1;
}
int main(){
cin>>m>>n;
for(int i=0;i<n;i++) cin>>g[i];
cout<<bfs()<<endl;
return 0;
}
题型三:剪枝
dfs{
if(现已经搜索的结果大于之前搜到的结果) return;
if(搜索物品条件(数目)已经达标)return;
for(遍历每个物品){
if(物体不满足最终主要条件) return;
if(此物品已经满足条件) {
物品进行标记;
dfs;
物品取消标记;
}
}
}
飞机降落
#include<bits/stdc++.h>
using namespace std;
int t,n,a[15][3];
bool st[15],flag;
void dfs(int k,int last){// 降落飞机数量 上一架飞机完成降落的时间
if(k>=n){//已经全部降落
puts("YES");
flag=true;
}
if(flag){
return;
}
for(int i=1;i<=n;i++){
if(!st[i]){//还未降落
if(a[i][1]<last) return;//最迟时间还未降落 就不满足
st[i]=true;
if(last<a[i][0]) dfs(k+1,a[i][0]+a[i][2]);//立马下降
else dfs(k+1,last+a[i][2]);//无法立马下降
st[i]=false;//否则无法下降
}
}
}
int main(){
cin>>t;
while(t--){
cin>>n;
memset(st,0,sizeof st);
for(int i=1;i<=n;i++){
cin>>a[i][0]>>a[i][1]>>a[i][2];
a[i][1]+=a[i][0];//最迟降落时间
}
flag=false;
dfs(0,0);
if(!flag) puts("NO");
}
return 0;
}
小猫爬山
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int cat[N],cab[N];
int n,w;
int ans;
bool cmp(int a,int b){
return a>b;
}
void dfs(int now,int cnt){//小猫的数量 缆车的数量
if(cnt>=ans){//如果已经超过最小的缆车数量 直接返回
return;
}
if(now==n+1){//小猫的数量
ans=min(ans,cnt);
return;
}
//尝试分配到已经租用的缆车上
for(int i=1;i<=cnt;i++){//分配到已经租用的缆车
if(cab[i]+cat[now]<=w){
cab[i]+=cat[now];
dfs(now+1,cnt);
cab[i]-=cat[now];//还原
}
}
//新开一辆缆车
cab[cnt+1]=cat[now];
dfs(now+1,cnt+1);
cab[cnt+1]=0;
}
int main(){
cin>>n>>w;
for(int i=1;i<=n;i++){
cin>>cat[i];
}
sort(cat+1,cat+1+n,cmp);
ans=n;
dfs(1,0);
cout<<ans<<endl;
return 0;
}
题型四:DFS连通性(计数)
迷宫(判断是否连通)
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n;
char g[N][N];
int xa,xb,ya,yb;
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
bool st[N][N];
bool dfs(int x,int y){
if(x==xb&&y==yb) return true;
st[x][y]=true;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=n) continue;
if(st[a][b]) continue;
if(g[a][b]=='#') continue;
if(dfs(a,b)) return true;
}
return false;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n;
for(int i=0;i<n;i++) cin>>g[i];
cin>>xa>>ya>>xb>>yb;
memset(st,0,sizeof st);
if(g[xa][ya]=='#'||g[xb][yb]=='#'){
cout<<"NO"<<endl;
}else{
if(dfs(xa,ya)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
红与黑(dfs联通块内计数)
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 25;
int n, m;
char g[N][N];
bool st[N][N];
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int dfs(int x, int y)
{
int cnt = 1;
st[x][y] = true;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= m) continue;
if (g[a][b] != '.') continue;
if (st[a][b]) continue;
cnt += dfs(a, b);//从最终一步一步返回dfs(a,b)=1, cnt+=dfs(a,b)
}
return cnt;
}
int main()
{
while (cin >> m >> n, n || m)
{
for (int i = 0; i < n; i ++ ) cin >> g[i];
int x, y;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == '@')
{
x = i;
y = j;
}
memset(st, 0, sizeof st);
cout << dfs(x, y) << endl;
}
return 0;
}
马走日(bfs联通块计数)
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int M=1000;
typedef pair<int,int>PII;
PII q[M];
const int N=1010;
int n,m,x,y;
bool d[N][N];
int dx[]={-2,-2,-1,-1,1,1,2,2};
int dy[]={1,-1,2,-2,2,-2,1,-1};
int bfs(int sx,int sy){
int cnt=0;
int hh=0,tt=0;
q[0]={sx,sy};
d[x][y]=true;
while(hh<=tt){
PII t=q[hh++];
for(int i=0;i<8;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=n||b<0||b>=m) continue;
if(d[x][y]!=false) continue;
cnt++;
if(a==x&&b==y){
return cnt;
}
d[a][b]=true;
q[++tt]={a,b};
}
}
}
int main(){
cin>>n>>m;
cin>>x>>y;
memset(d,false,sizeof d);
cout<<bfs(x,y);
return 0;
}
全球变暖(联通块内加条件)
#include<bits/stdc++.h>
using namespace std;
int n;
char a[1010][1010]; //地图
int vis[1010][1010]={0}; //标记是否搜过
int d[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}}; //四个方向
int flag; //用于标记这个岛中是否被完全淹没
void dfs(int x, int y){
vis[x][y] = 1; //标记这个'#'被搜过。注意为什么可以放在这里
if(a[x][y+1]=='#' && a[x][y-1]=='#' && a[x+1][y]=='#' && a[x-1][y]=='#')
flag = 1; //上下左右都是陆地,不会淹没
for(int i = 0; i < 4; i++){ //继续DFS周围的陆地
int nx = x + d[i][0], ny = y + d[i][1];
//if(nx>=1 && nx<=n && ny>=1 && ny<=n && vis[nx][ny]==0 && a[nx][ny]=='#') //题目说边上都是水,所以不用这么写了
if(vis[nx][ny]==0 && a[nx][ny]=='#') //继续DFS未搜过的陆地,目的是标记它们
dfs(nx,ny);
}
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin >> a[i][j];
int ans = 0 ;
for(int i = 1; i <= n; i++) //DFS所有像素点
for(int j = 1; j <= n; j++)
if(a[i][j]=='#' && vis[i][j]==0){
flag = 0;
dfs(i,j);
if(flag == 0) //这个岛全部被淹
ans++; //统计岛的数量
}
cout<<ans<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n;
char a[1010][1010];
bool st[1010][1010];
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
int flag;
void dfs(int x,int y){
st[x][y]=true;
if(a[x][y+1]=='#'&&a[x][y-1]=='#'&&a[x+1][y]=='#'&&a[x-1][y]=='#') flag=1;//上下都是陆地不会被淹没
for(int i=0;i<n;i++){
int ax=x+dx[i],by=y+dy[i];
if(st[ax][by]==true) continue;
if(ax<=0||ax>n||by<=0||by>0) continue;
if(a[ax][by]=='#') dfs(ax,by);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
memset(st,false,sizeof st);
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]=='#'&&st[i][j]==false){
flag=0;
dfs(i,j);
if(flag==0){//这个岛全部被淹
ans++;
}
}
}
}
cout<<ans<<endl;
return 0;
}
功夫传人(bfs)
#include<bits/stdc++.h>
using namespace std;
int big[110000],d[110000];
vector<int> p[110000];
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n;
double z,r,sum=0.0;
cin>>n>>z>>r;//师门总人数 祖师爷功力值 折扣百分比值
r=(1-r/100.0);//功力逐渐递减
for(int i=0;i<n;i++){
int k,x;
cin>>k;
if(!k){//得道者
cin>>x;
big[i]=x;//i号功力被放大x倍
}
for(int j=0;j<k;j++){
cin>>x;
p[i].push_back(x);//i人的子弟
}
}
int t;
queue<int> q;
q.push(0);//祖师爷是根节点
d[0]=0;
while(!q.empty()){
t=q.front();
q.pop();
for(int i=0;i<p[t].size();i++){
d[p[t][i]]=d[t]+1;//代数增加 所以功力逐渐减少 (树的层数)
if(big[p[t][i]]){//得道者
sum+=z*pow(r,d[p[t][i]])*big[p[t][i]];
}else{
q.push(p[t][i]);
}
}
}
if(n==1&&big[0]) sum=z*big[0];
cout<<(int)sum<<endl;
return 0;
}