20260520-初级班-深度优先搜索

已结束 IOI 开始于: 2026-6-3 15:30 4 小时 主持人: 21

深度优先搜索

深度优先搜索的本质是以一种有规律的形式去遍历所有的可能情况。

全排列问题

背景:3个同学来排队,有哪几种排队方法

1.For循环暴力枚举

int vis[4]={0};
for(int i=1;i<=3;i++){
    vis[i]=1;
    for(int j=1;j<=3;j++){
        if(vis[j]) continue;
        vis[j]=1;
        for(int x=1;x<=3;x++){
            if(vis[x]) continue;
            cout<<i<<" "<<j<<" "<<x<<"\n";
        }
        vis[j]=0;
    }
    vis[i]=0;
}

其中使用了vis数组,进行了回溯操作。如果同学的个数逐渐增多,

我们很难再使用for循环,可以使用递归的方式来解决问题。这种递归+回溯的遍历方式就是搜索。

2.搜索暴力枚举

int vis[4];
int a[4];
void dfs(int x){
    if(x==4){
        cout<<a[1]<<" "<<a[2]<<" "<<a[3]<<"\n";
        return;
    }
    for(int i=1;i<=3;i++){
        if(vis[i]) continue;
        vis[i]=1;
        a[x]=i;
        dfs(x+1);
        vis[i]=0;
    }
}

像刚刚这种,一条线走到底的方式,我们叫做深度优先搜索,每次都会把选定的某条路走完再走下一条路。

连通块问题

背景:有一张3*3的地图,其中-表示平地,#表示山,山有可能是连绵的。

如何找到所有的山?

我们可以使用搜索把一片山全都标记了,搜索了几次,就是有多少山。

int fx[4][2]={0,1,1,0,0,-1,-1,0};
int vis[100][100];
void dfs(int x,int y){
   	vis[x][y]=1;
    for(int i=0;i<4;i++){
        int xx=fx[i][0]+x;
        int yy=fx[i][1]+x;
        if(xx<1||xx>n||yy<1||yy>m||vis[xx][yy]||mp[xx][yy]=='-') continue;
        dfs(xx,yy);
    }
}
int main(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!vis[i][j]&&mp[i][j]=='-'){
                ans++;
                dfs(i,j);
            }
        }
    }
}

涂色部分代码

#include<bits/stdc++.h>
using namespace std;
int fx[4][2]={0,1,1,0,0,-1,-1,0};
int n,m;
int mp[200][200];
int vis[200][200];
void dfs(int x,int y){
	for(int i=0;i<4;i++){//四个方向 
		int xx=x+fx[i][0];
		int yy=y+fx[i][1];
		 if(xx<1||xx>n||yy<1||yy>n){//越界 
		 	continue; 
		 }
		 if(mp[xx][yy]==1){
		 	continue;
		 }
		 if(vis[xx][yy]==1){
		 	continue;
		 }
		 vis[xx][yy]=1;
		 dfs(xx,yy);
	}
}
int main(){
	
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++) cin>>mp[i][j];
	}
	for(int j=1;j<=n;j++){//处理第一行 
		if(mp[1][j]==0&&!vis[1][j]){
		
		}
	}
	for(int j=1;j<=n;j++){//处理最后一行 
		if(mp[n][j]==0&&!vis[n][j]){
			
		}
	}
	
	for(int i=1;i<=n;i++){//处理左列 
		if(mp[i][1]==0&&!vis[i][1]){
		
		}
	}
	for(int i=1;i<=n;i++){//处理右列 
		if(mp[i][n]==0&&!vis[i][n]){
			
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(?) cout<<2<<" ";
			else cout<<mp[i][j]<<" ";
		}
		cout<<"\n";
	} 
	
}

枚举所有情况


int n,ans=10000000;
void dfs(int x,int v){
	if(x==n+1){
		ans=min(ans,v);
		return;
	} 
	if(v>=a[x]){
		dfs(x+1,v-a[x]);
	}
	dfs(x+1,v);
}
int main(){
	int v;cin>>v;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	dfs(1,v);
} 
状态
已结束
规则
IOI
题目
7
开始于
2026-6-3 15:30
结束于
2026-6-3 19:30
持续时间
4 小时
主持人
参赛人数
21