搜索入门(dfs,bfs)

这种题的标志:做一件事情有很多步骤,每一个步骤有几个方法,寻找最优(短)步骤。

dfs深度优先搜索,优先向深度寻找,没有下一个节点后返回寻找上一个节点的其他分支直到全部搜索

return后放函数(递归),其实就是下一步要做什么

void dfs(int deep/*........*/)//参数用来表示状态  
{  
    if(/*到达终点状态、找到解*/)  
    {  
        //根据题意添加  
        return;      //回溯
    }  
    if(/*越界或者是不合法状态,减枝*/)  
        return;  
    for(/*尝试每一种可能*/)  
    { 
        if(/*状态合法*/)  
        {  
            //根据题意来添加  
            //标记;  
            dfs(deep+1);  //下一种情况
            //(还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
 
    }  
}  
//棋盘问题
void search(int hang)
{
	int i;
	if (num == k)
	{
		sum++;
		return;
	}
	if (hang >= n)
	{
		return;
	}
	for (i = 0; i < n; i++)
	{
		if (vis[i] == 0 && a[hang][i] == '#')
		{
			vis[i] = 1;
			num++;
			search(hang + 1);
			vis[i] = 0;
			num--;
		}
	}
	search(hang + 1);
}
void dfs(int num, int max1, int min1, int sum)
{                                   //当前题目下标数(深度)、最大值、最小值、难度总和
	if (num == n + 1)
		return;
	if (sum <= maxx && sum >= minn && max1 - min1 >= dif && num == n)
		ans++;
	dfs(num + 1, max(max1, a[num]), min(min1, a[num]), sum + a[num]);		
                                        //下一种情况,取max(min)代表当前最大(小)
	dfs(num + 1, max1, min1, sum);				//代表从现在开始搜索,不包括之前
}

dfs(0, 0, inf, 0);
//折半搜索
int n, m;
ll k, a[maxn][maxn], ans;
map<ll, ll> mp[maxn];       //存储行,各异或值个数,以及异或值(多个)
void dfs1(int x, int y, ll now) 
{
	if (x + y == (n + m + 2) / 2) 
	{
		mp[x][now]++;		//记录左上角的每一种路径和(值和个数)
		return;
	}
	if (x < n) 
		dfs1(x + 1, y, now ^ a[x + 1][y]);
	if (y < m) 
		dfs1(x, y + 1, now ^ a[x][y + 1]);
}
void dfs2(int x, int y, ll now) 
{
	if (x + y == (n + m + 2) / 2) 
	{
		ans += mp[x][now ^ k ^ a[x][y]];        
		//x为行,第二个中括号是右下角的一条路径和(不包括“中间”)与k异或,
        //如果与mp里面存的左上角的路径和相同,mp值会显示个数,否则为0
		return;
	}
	if (x > 1)
		dfs2(x - 1, y, now ^ a[x - 1][y]);
	if (y > 1) 
		dfs2(x, y - 1, now ^ a[x][y - 1]);
}

	dfs1(1, 1, a[1][1]);
	dfs2(n, m, a[n][m]);
//记忆化搜索
ll dp[maxn][2], a[maxn], n;
ll dfs(ll x, ll d)		//d是0或1
{
	ll temp;
	if (x <= 0 || x > n)
		return 0;
	else if (dp[x][d] != 0)		//是否出现过
		return dp[x][d];
	else
		dp[x][d] = -1;		//第一次遇到记为-1,若重复就是-1,否则赋值
	if (d !=0)					//先加后减循环到x出边界
		temp = dfs(x + a[x], 0);
	else
		temp = dfs(x - a[x], 1);
	if (temp == -1)
		return -1;
	else
		return dp[x][d] = a[x] + temp;
}

for (i = 1; i < n; i++)
{
	ll ans;
	a[1] = i;
	dp[1][1] = 0;
	ans = dfs(1, 1);
	printf("%I64d\n", ans);
}

bfs宽度优先搜索,优先同一深度寻找,同一深度搜索完后,搜索下一个深度

//C语言版
struct Node
{
	int x;
	int step;
}queue[maxn];
int bfs()
{
	int i, head = 0, tail = 1;		//为下一行储存在queue中的队首、队末下标
	Node now, next;		        //now为当前级别(行),next为下一级别(行)
	queue[0] = { n,0 };
	vis[n] = 1;
	while (head < tail)
	{
		now = queue[head++];    //每次从队列的头取出一个元素,查看这个元素的下一级元素
		for (i = 0; i < 3; i++)
		{
			switch (i)
			{
			case 0:next.x = now.x - 1; break;
			case 1:next.x = now.x + 1; break;
			case 2:next.x = now.x * 2; break;
			}
			if (next.x < 0 || next.x >= maxn)
				continue;
			if (vis[next.x] == 0)
			{
				vis[next.x] = 1;
				next.step = now.step + 1;
				queue[tail++] = next;        //将下一级元素放到队列末尾
				if (next.x == k)
					return next.step;        //找到时结束
			}
		}
	}
}
//c++ stl版
struct node
{
    int x;
    int y;
    int z;
    int step;
};
int dir[6][3] = { {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
char m[maxn][maxn][maxn];
int vis[maxn][maxn][maxn];
queue<node>que;    
//首先创建一个visit[ ]数组和一个队列q,分别用来判断该位置是否已经访问过及让未访问过的点入队
int bfs(node s, node e)
{ 
    node now, next;
    int i;
    memset(vis, 0, sizeof(vis));
    while (!que.empty())        //多次使用bfs函数,初始化visit[ ]数组,清空q队列
        que.pop();
    s.step = 0;
    vis[s.x][s.y][s.z] = 1;     //让起点start入队,并使该点的visit置1
    que.push(s);
    while (!que.empty())        //while(!q.empty()){......}执行搜索操作
    {
        now = que.front();      //取出队头元素后使队头元素出队,判断该元素是否为目标到达点
        que.pop();
        if (now.x == e.x && now.y == e.y && now.z == e.z)
            return now.step;        //如果是目标点,就返回结果(一般是最短时间、最短路径)
//如果不是目标点,就继续访问与其相邻的位置点,将可走的相邻的位置点入队,并更新visit[ ]数组
        for (i = 0; i < 6; i++)     
        {
            next.x = now.x + dir[i][0];
            next.y = now.y + dir[i][1];
            next.z = now.z + dir[i][2];
            if (next.x >= 1 && next.x <= L && next.y >= 1 && next.y <= R && next.z >= 1 && next.z <= C)
                if(m[next.x][next.y][next.z] != '#' && !vis[next.x][next.y][next.z])
                {
                    vis[next.x][next.y][next.z] = 1;
                    next.step = now.step + 1;
                    que.push(next);
                }
        }
    }
    return -1;
}
struct node
{
	int num;
	int step;
};
int vis[maxn];
queue<node>que;
int bfs(int a,int b)
{ 
	node now, next;
	int i,j;
	memset(vis, 0, sizeof(vis));
	while (!que.empty())      
		que.pop();
	vis[a]= 1;
	now = { a,0 };
	que.push(now);
	while (!que.empty())
	{
		now = que.front();
		que.pop();
		for (j = 0; j < 4; j++)
		{
			for (i = 0; i <= 9; i++)
			{
				switch (j)
				{
				case 0:next.num = now.num - now.num % 10 + i; break;
				case 1:next.num = now.num - now.num % 100 + now.num % 10 + i * 10; break;
				case 2:next.num = now.num - now.num % 1000 + now.num % 100 + i * 100; break;
				case 3:if (i == 0)continue; next.num = now.num % 1000 + i * 1000; break;
				}
				if (vis[next.num] == 0&&is(next.num))
				{
					vis[next.num] = 1;
					next.step = now.step + 1;
					que.push(next);
					if (next.num == b)
						return next.step;
				}
			}
		}
	}
	return -1;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值