C++ 算法篇 深度优先搜索(DFS)习题答案

1、瓷砖

#include<bits/stdc++.h>
using namespace std;
int a[51][51]={0},ans=0;
void dfs(int x,int y)
{   ans++;
    a[x][y]=false;
    if(a[x-1][y]) dfs(x-1,y);
    if(a[x+1][y]) dfs(x+1,y);
    if(a[x][y-1]) dfs(x,y-1);
    if(a[x][y+1]) dfs(x,y+1);
}
int main()
{   int i,j,w,h,dx,dy;
    char c;
    cin>>w>>h;
    for(i=1;i<=h;i++)
      for(j=1;j<=w;j++)
      {  c=getchar();
         if(c=='.') a[i][j]=1;
         if(c=='@') { a[i][j]=1; dx=i;dy=j;} 		      
      }
    dfs(dx,dy);    
    cout<<ans;
}

2、最大黑色区域

#include<bits/stdc++.h>
using namespace std;
int n, m, sum;
int a[101][101];
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; 
void dfs(int x, int y) {
    a[x][y] = 0; //每遇到一次1,结果加1,然后赋值为0,避免被再次搜索 
    for(int t = 0; t < 4; t++)//四个方向搜索
	{   int nx = x + dir[t][0];
        int ny = y + dir[t][1];
        if(nx >= 0 && nx < n && ny >= 0 && ny < m && a[nx][ny] == 1) 
		{   sum++; 
            dfs(nx, ny);
        }
    }
    return;
}

int main()
{   scanf("%d %d", &n, &m);
    int i, j, max = 0;
    for(i = 0; i < n; i++) 
        for(j = 0; j < m; j++) scanf("%d", &a[i][j]);            
    for(i = 0; i < n; i++)   //每次遇到黑点就开始向四个方向开始搜索 
	   for(j = 0; j < m; j++) 
	        if(a[i][j] == 1)
	        {   sum = 1;
                dfs(i, j);
                if(sum > max) max = sum;  //结果更新为最大的那个          
            }
        printf("%d\n", max);
    return 0;
}

3、数的拆分

#include<bits/stdc++.h>
using namespace std;
int a[10001]={1},n,total;
int print(int t)
{   cout<<n<<"=";
    for (int i=1;i<=t-1;i++)    //输出一种拆分方案             
            cout<<a[i]<<"+";
    cout<<a[t]<<endl;
    total++;                   //方案数累加1  
}
int search(int s,int t)
{   int i;
    for (i=a[t-1];i<=s;i++)
        if (i<n)                //当前数i要大于等于前1位数,且不过n
        {  a[t]=i;              //保存当前拆分的数i
           s-=i;                //s减去数i, s的值将继续拆分
           if (s==0) print(t);  //当s=0时,拆分结束输出结果
           else search(s,t+1);  //当s>0时,继续递归
           s+=i;                //回溯:加上拆分的数,以便产分所有可能的拆分  
        }
}
int main()
{   cin>>n;
    search(n,1);                        //将要拆分的数n传递给s
    cout<<"total="<<total<<endl;        //输出拆分的方案数
}

P1238 走迷宫

#include<bits/stdc++.h>
using namespace std;
int LJ[50000][2];//用来记录每步的坐标;
int ax,ay,bx,by,k,pd;//ax,ay代表起点,bx,by代表终点,k是步数;
int cx[4]={0,-1,0,1};
int cy[4]={-1,0,1,0};//四个方向,左上右下;
bool temp[17][17];//标记:已经走过的路;
int MAP[17][17];//地图:1可走,0不可走;

void print()//输出函数;
{   if(pd==0)  pd=1;  //pd:判断是否有解,有解=1,无解=0;    
    for(int h=0;h<=k-1;h++)
    cout<<"("<<LJ[h][0]<<","<<LJ[h][1]<<")"<<"->"; //输出中途步骤;
    cout<<"("<<bx<<","<<by<<")"<<endl;//输出终点;
}

void walk(int x,int y)//搜索回溯主体;
{   if(x==bx&&y==by)  print();//到达边界输出;    
    else
    {   for(int i=0;i<=3;i++)
        if(MAP[x+cx[i]][y+cy[i]]==1&&temp[x+cx[i]][y+cy[i]]==0)//判断下一步是否可以走,一方面判断路是否可走,另一方面判断自己是否走过这条路;
        {   temp[x][y]=1;//走过的路打上标记;
            LJ[k][0]=x;
            LJ[k][1]=y;//记录当前的坐标
            k++;//步数加1;
            walk(x+cx[i],y+cy[i]);
            temp[x][y]=0;
            k--;
            //回溯,这里的LJ可以不用恢复;
        }
    }
}
int main()
{
    int m,n;//矩阵长宽;
    cin>>m>>n;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            cin>>MAP[i][j];//输入地图;
            
    cin>>ax>>ay;//起点;
    cin>>bx>>by;//终点;
    walk(ax,ay);//开始搜索;
    if(pd==0)  cout<<"-1";    //判断是否有解,如果没有解,输出-1;   
    return 0;
}

P1219 [USACO1.5]八皇后

#include<bits/stdc++.h>
using namespace std;
int a[1000],b[1000],c[1000],d[1000],n,s;
    //a存行
    //b存列
    //c存左下到右上的对角线(行+列的和相同)
    //d存右下到左上的对角线(行-列的差相同)
    //清零数组
void print(){
    int i;s++;
    for(i=1;i<=n;i++)cout<<a[i]<<" ";
    cout<<endl;
    }
int search(int i){
    int j;
    for(j=1;j<=n;j++)
        if(b[j]==0&&c[i+j]==0&&d[i-j+n]==0){//判断
            a[i]=j;//写进去(第i行第j个) 
            b[j]=1;//占行 
            c[i+j]=1; d[i-j+n]=1;//占对角线 
            if(i==n)print();//满足条件输出 
            else search(i+1);//继续推 
            b[j]=0;c[i+j]=0;d[i-j+n]=0;//回溯
        }
    return 0;
    }
int main(){
    cin>>n;
    search(1); 
    cout<<s<<endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值