DFS搜索问题

*(寒假训练第一天)

今日DFS搜索问题如下:
1. P1162 填涂颜色
2. P1605 迷宫
3. P1036 [NOIP2002 普及组] 选数
4. P2392 kkksc03考前临时抱佛脚
(一) 收获最大的还是填涂颜色问题:
题目中数字矩阵有0和1两种数字,要求将1包围的数字0全部变 为2并输出变换后的矩阵;

思考:这里可以将 1 包围的 0 和在外围的 0 ,通过深度优先搜索标记 区分开来,比如将外围的 0 变为3,被包围的 0 不变化即可。

#include<iostream>
using namespace std;
const int N = 1000;
int n,a[N][N];
int x[4] = {-1,1,0,0};//上下左右
int y[4] = {0,0,-1,1};
void dfs(int p,int q){
    int i;
    //此处条件是不超出矩阵边界,且这个点不是 1 (1相当于迷宫问题的墙壁)
    if (p<0 || p>n+1 || q<0 || q>n+1 || a[p][q]!=0) return;
    a[p][q] = 3;
    for (i=0;i<4;i++) dfs(p+x[i],q+y[i]);//向四个方向搜索
}
int main()
{
	cin>>n;
	for(int i = 1;i<=n;i++)
	for(int j = 1;j<=n;j++)
	{
		cin>>a[i][j];
	}
	dfs(0,0);//此处一定是从矩阵为零的点出发,满足 a[p][q]!=0的条件,由于矩阵从(1,1)开始有值,所以从(0,0)开始肯定不会影响结果。如果从(1,1)开始但是(1,1)处为 1 会导致结果不正确 
	cout<<endl;
    for(int i = 1;i<=n;i++){
		for(int j = 1;j<=n;j++)
		{
			if(j!=1) cout<<" ";
			if(a[i][j]==3) cout<<"0";
			else if(a[i][j]==0) cout<<"2";
			else cout<<a[i][j];
		} 
		cout<<endl;
  }
}

(二)迷宫
(1)迷宫问题主要注意开始点要在搜索前进行标记,否则容易产生错误。
(2)再搜索过一个点后要还原标记点避免对下一次搜索产生影响。

for(int i = 0;i<4;i++)
    {
        //选择一个移动方向
        int x1 = s.x + x[i];
        int y1 = s.y + y[i];
        //判断移动方向是否合理
        if(x1>=0 && y1>=0 && x1<m && y1<n && map[x1][y1])
        {
            cnt++;
            map[x1][y1] = 0;//可进行移动标记状态为已经过
            way[cnt].x = x1;//记录移动路径
            way[cnt].y = y1;
            dfs(way[cnt]);//在当前可移动的点继续深度搜索可行的移动位置
            map[x1][y1] = 1;//将标记状态还原,以免对下一步选择的方向造成影响
            cnt--;
        }
    }

(三)选数问题
这个我感觉有点难理解,还有待提高。

#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 1e6;
int a[maxn],n,k,count,ans;
int F(int k)
{
	if(k == 1) return 0;
	for(int i = 2;i<=sqrt(k);i++)
	{
		if(k%i == 0) return 0;
	}
	return 1;
}
void dfs(int sum,int count,int start)
{
	if(count == k && F(sum)) ans++;
	
	for(int i = start;i<n;i++)
	{
		dfs(sum+a[i],count+1,i+1);
	}
}
int main()
{
	cin>>n>>k;
	for(int i = 0;i<n;i++)
	cin>>a[i];
	dfs(0,0,0);
	cout<<ans<<endl;
	return 0;
} 

今天一天,主要进行了搜索问题的训练,但总体感觉不是很好,有的问题做起来依然吃力,搜索 这一块问题,我相信在寒假过后会有更好的理解。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值