DFS 和BFS 搜索问题

One.写代码技巧

待补全

Two.搜索问题
知道它们各自的酸度 ss 和苦度 bb。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
#include<bits/stdc++.h>
using namespace std;
const int M=15;//养成良好习惯
int a[M],b[M],n,ans=0x7fffffff;
//ans初始化为最大值
void dfs(int i,int x,int y){
//i是表示目前的配料编号,x为酸度,y为甜度
    if(i>n)
    {
    	//注意,必须大于n才表示全部搜完
        if(x==1&&y==0)return;
        //判断清水的情况
        ans=min(abs(x-y),ans);
        //更新ans
        return;
    }
    //分两种情况搜索:1添加 2不添加
    dfs(i+1,x*a[i],y+b[i]);
    dfs(i+1,x,y); 
    //这题无需回溯,不明白为何有些题解居然还用全局变量,非得回溯-_-||
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i],&b[i]);
        //读入,用cin太慢了
    }
    dfs(1,1,0);
    printf("%d\n",ans);
    return 0;
}
Three.全排列问题,(递归解决)
#include<bits/stdc++.h>
using namespace std;
int num=0;
void search(int begin,int end,int * date)
{
    if(begin==end)
    {
        for(int i=0;i<=end;i++)
        {
            cout<<date[i];
        }
        cout<<endl;
        num++;
    }
    else
    {
        for(int i=begin;i<=end;i++)
        {
            swap(date[begin],date[i]);
            search(begin+1,end,date);
            swap(date[begin],date[i]);
        }
    }
}
int main()
{
    int date[10]={1,2,3,4,5,6,7,8,9,10};
    search(0,2,date);
    cout<<num;
}

其中search中内容可以修改,0代表的是date【0】

Four.全排列,子集全排列
#include<bits/stdc++.h>
using namespace std;
int num=0;
void search(int begin,int end,int * date)
{
    if(begin==3)
    {
        for(int i=0;i<=end;i++)
        {
            cout<<date[0]<<date[1]<<date[2]<<endl;
        }
        num++;
    }
    else
    {
        for(int i=begin;i<=end;i++)
        {
            swap(date[begin],date[i]);
            search(begin+1,end,date);
            swap(date[begin],date[i]);
        }
    }
}
int main()
{
    int date[10]={1,2,3,4,5,6,7,8,9,10};
    search(0,4,date);
    cout<<num;
}

在1,2,3,4,5中选出3个数进行全排列,总共有60中可能;

Five.打印n个数中任意m个数的组合 即求Cmn的值
#include<iostream>
using namespace std;
void fl(int n,int m)
{
    for(int i=0;i<(1<<n);i++)
    {
        int kk=i,num=0;
        while(kk)
        {
            kk=kk&(kk-1);//进行计算,求m,需要取多少位
            num++;
        }
        if(num==m)
        {
        for(int j=0;j<n;j++)
        {
            if(i & (1<<j))
            {
                cout<<j<<" ";
            }
        }
        cout<<endl;
        }
       
    }
}
int main()
{
    fl(5,3);
    return 0;
}   

意思是在5个数里面选择3个数,进行全排列,其中,使用了位运算
1<<2 为2^2,<<为移动位的符号,为右移动

Six.打印n个数的任意组合
#include<iostream>
using namespace std;
void fl(int n)
{
    for(int i=0;i<(1<<n);i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i & (1<<j))
            {
                cout<<j<<" ";
            }
        }
        cout<<endl;
       
    }
}
int main()
{
    fl(3);
    return 0;
}  
Seven.广度优先搜索bfs 运用队列实现(红黑地砖问题)
#include<bits/stdc++.h>
using namespace std;
int w,h,num=0;
char room[20][20];
int dv[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct st
{
    int x,y;
};
bool check(int x,int y)
{
    if(x>=0&& x<w && y>=0 && y<h) return 1;
    else return 0;
}
//2.广度优先搜索
void bfs(int x,int y)
{
    num=1;
    queue<st> brick;
    st start,next;
    //用队列实现广度优先搜索
    start.x=x;
    start.y=y;
    brick.push(start);
    while(!brick.empty())
    {
        start=brick.front();
        //next 的输入,方向变换,并且用check判断是否出界
        for(int i=0;i<4;i++)
        {
            next.x=start.x+dv[i][0];
            next.y=start.y+dv[i][1];
            if(check(next.x,next.y) && room[next.x][next.y]=='.')
            {
                room[next.x][next.y]='#';
                num++;
                brick.push(next);
            }
        }
        brick.pop();
    }

}
int main()
{
    int X,Y;
    cin>>w>>h;
    //1.输入数据
    for(int i=0;i<w;i++)
    {
        for(int j=0;j<h;j++)
        {
            cin>>room[i][j];
            if(room[i][j]=='@')
            {
                X=i;
                Y=j;
            }
        }
    }
    bfs(X,Y);
    //3.输出数据
    cout<<num;
    return 0;
}
Eight.用dfs解决红黑地砖问题
void dfs(int x,int y)
{
//初始化,进来的每一个坐标
    room[x][y]='#';
    num++;//路径增加
    st start ,next;
    start.x=x;
    start.y=y;
    for(int i=0;i<4;i++)
        {
            next.x=start.x+dv[i][0];
            next.y=start.y+dv[i][1];
            if(check(next.x,next.y) && room[next.x][next.y]=='.')
            {
                dfs(next.x,next.y);//用递归的方式,深度搜索
            }
        }
}

其他不变,dfs函数

Nine.八皇后问题dfs
#include<bits/stdc++.h>
using namespace std;
int num=0,damier[15],n,a[20],b[20],c[20],d[20];
void dfs(int r)//dfs 搜索
{
    if(r==n+1)//一行一行搜索
    {
        //出口,以及输出位置
        num++;
        if(num<=3)
        {
            for(int i=1;i<=n;i++)
            {
                cout<<a[i]<<" ";
            }
            cout<<endl;
        }
        return; 
    }
    for(int i=1;i<=n;i++)
    {
        if(!b[i] && !c[i+r] && !d[r-i+n])
        //减枝操作,同一行,同一列,同一斜行
        {
            a[r]=i;//皇后的位置,他在第r行i位置
            b[i]=1;//第i列为1,说明不能再用了,b【】代表的是列
            c[i+r]=1;
            //c【】代表的是主对角线 y=x 这样只要是对角线,之和是一样的
            d[r-i+n]=1;//d【】代表的是副对角线,之差是一样的,保证为正
            dfs(r+1);
            b[i]=0;//如果不通过,则恢复之前的状态
            c[i+r]=0;
            d[r-i+n]=0;
        }
    }

}
int main()
{
    cin>>n;
    dfs(1);//从1开始搜索
    cout<<num;
    return 0;
}
Ten.连通块问题搜索

思路
1.输入 2. 搜索 3. 输出
其中,因为存在连通块,所以思路是从外部开始搜索,直到,无法搜索。
而搜索点,不单单要从0,0 开始,要从,边界任何一个可以进去的点开始

#include<bits/stdc++.h>
using namespace std;
int n,a[31][31];
void dfs(int x,int y)
{
    if(x<0||x>n||y<0||y>n||a[x][y]!=0) return ;
    //如果不符合,返回上一步
    a[x][y]=3;
    dfs(x+1,y);
    dfs(x,y+1);
    dfs(x-1,y);
    dfs(x,y-1);//在走方位,可以不用循环,直接写
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cin>>a[i][j];
        }
    }
    for(int i=0;i<n;i++)
    {
    if(a[i][0]!=1) dfs(i,0);
    if(a[i][n-1]!=1) dfs(i,n-1);//搜第i行的第一列和第n列 
    }
    for(int i=0;i<n;i++)
    {
    if(a[0][i]!=1) dfs(0,i);
    if(a[n-1][i]!=1) dfs(n-1,i);//搜第i列的第一行和第n行 
    } 
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a[i][j]==1) cout<<a[i][j]<<" ";
            else if(a[i][j]==0) cout<<a[i][j]+2<<" ";
            else if(a[i][j]==3) cout<<a[i][j]-3<<" ";
        }
        cout<<endl;
    }
    return 0;
}
Eleven.马的遍历问题

队列的应用,队列实现的bfs,广度优先搜索,其中,进来的以一个数据,由他进行四周发散,符合条件的入队,这样会进来n个方向符合条件的,这样这个点,遍历完毕,从队列中弹出,那么刚才符合条件进来的点,每一个又会作为队头,进行遍历,进入符合条件的点,这就形成了遍历

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y;
int ans[410][410]={0};
bool a[410][410]={0};
struct st
{
    int x,y;
};
int dir[8][2]={{1,2},{1,-2},{2,1},{2,-1},{-1,2},{-1,-2},{-2,1},{-2,-1}};//八个方向的遍历
void bfs(int x,int y)
{
    a[x][y]=true;//初始进入的数据,trrue
    ans[x][y]=0;//开始为0
    queue<st> brick;
    st begin,start,next;
    begin.x=x;
    begin.y=y;
    brick.push(begin);//入队列,开始进行遍历
    while(!brick.empty())//如果不为空,说明还有点
    {
        start=brick.front();
        for(int i=0;i<8;i++)
        {
            next.x=start.x+dir[i][0];//各个方向的点
            next.y=start.y+dir[i][1];//方向处理
            if(next.x>0 && next.x<=n && next.y>0 &&next.y<=m && !a[next.x][next.y])//满足条件的,才能入列
            {
                ans[next.x][next.y]=ans[start.x][start.y]+1;
                a[next.x][next.y]=true;//标记走过了
                brick.push(next);//记得入队列
            }
        }
        brick.pop();//把队头弹出
    }
}
int main()
{
    memset(a,false,sizeof(a));//没有走过的是false
    memset(ans,-1,sizeof(ans));//对数组初始化
    cin>>n>>m>>x>>y;
    bfs(x,y);//广度优先搜索
    //输出数据
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            printf("%-5d",ans[i][j]);
        }
        cout<<endl;
    }
    return 0;
}
注意

考虑回溯问题,如果搜索不到,应该返回上一步,在使用dfs的时候应该注意。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值