ACM算法题第七周

本文讲述了四个编程题目,涉及迷宫路径、数字排列、矩阵连通区域和跳棋皇后放置,展示了如何用C++实现相关算法,包括深度优先搜索、回溯法和逻辑判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一题:

机器猫被困在一个矩形迷宫里。

迷宫可以视为一个 n×m 矩阵,每个位置要么是空地,要么是墙。机器猫只能从一个空地走到其上、下、左、右的空地。

机器猫初始时位于 (1,1) 的位置,问能否走到 (n,m) 位置。

输入格式

第一行,两个正整数 n,m。

接下来 nn 行,输入这个迷宫。每行输入一个长为 m 的字符串,# 表示墙,. 表示空地。

输出格式

仅一行,一个字符串。如果机器猫能走到 (n,m),则输出 Yes;否则输出 No

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[105][105];
bool escape;
int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};
void dfs(int x,int y){
    if(x<1||x>n||y<1||y>m) return;
    if(x==n&&y==m) escape=1;
    if(escape) return; 
    for(int i=0;i<4;i++){
        if(a[x+dx[i]][y+dy[i]]!='#'){
            a[x+dx[i]][y+dy[i]]='#';
            dfs(x+dx[i],y+dy[i]);
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    a[1][1]='#';
    dfs(1,1);
    if(escape==1) cout<<"Yes";
    else cout<<"No";
    return 0;

解题思路:

        本题新定义dx、dy数组用于表示移动方向,然后从(1,1)开始,如果移动后符合条件且未遇到障碍,那么从这个点开始下一次移动,并把这个点标记为障碍。依次搜索下去,如果越界则结束,如果恰好走到终点,就把escape赋值为1然后结束

第二题:

按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n。

输出格式

由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5 个场宽。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[10],b[10];
void dfs(int step){
    if(step==n+1){
        for(int i=1;i<=n;i++){
            printf("%5d",a[i]);
        }
        cout<<endl;
        return;
    }
        for(int i=1;i<=n;i++){
            if(b[i]==0){
                a[step]=i;
                b[i]=1;
             dfs(step+1);
            b[i]=0;
            }
        }
}
int main(){
    cin>>n;
    dfs(1);
    return 0;
}

解题思路:

定义a,b两个数组一个用来表示全排列,一个用来记录数字是否使用过。dfs函数中,先判断step即存放的数字数目是否到达n+1,如果到达则输出数组a,并返回上一个dfs;如果没达到,那么从1开始遍历,遇到第一个未使用的数就存放进a数组,然后进行下一位的数字存放,并进入下一个dfs,当全部遍历后,函数结束。

第三题:

一矩形阵列由数字 0 到 9 组成,数字 1 到 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。

输入格式

第一行两个整数代表矩阵大小 n 和 m。

接下来 nn 行,每行一个长度为 m 的只含字符 0 到 9 的字符串,代表这个 n×m 的矩阵。

输出格式

一行一个整数代表细胞个数。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
int a[105][105];
int dx[4]={1,0,0,-1};
int dy[4]={0,1,-1,0};
void dfs(int x,int y){
    a[x][y]=0;
    for(int i=0;i<4;i++){
        x+=dx[i];
        y+=dy[i];
        if(x>0&&x<=n&&y>0&&y<=m&&a[x][y]!=0){
            dfs(x,y);
        }
        x-=dx[i];
        y-=dy[i];
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%1d",&a[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]==0) continue;
            dfs(i,j);
            cnt++;
        }
    }
    cout<<cnt;
    return 0;
}

解题思路:

设置dx、dy两个数组表示四个移动方向,然后开始遍历每个点,如果该点数据为0,则跳过;如果不是,那么进入dfs函数。dfs函数中,遍历dx、dy四个方向,如果四个方向中仍有非零的,那么就赋值为零,直到把这一整块相连的非零都赋值为零,然后计数并搜索下一块。

第四题:

一个如下的 6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2 4 6 1 3 5 来描述,第 i 个数字表示在第 i 行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。

输入格式

一行一个正整数 n,表示棋盘是 n×n 大小的。

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,ans;
int a[30],b[30],c[30],d[30];
void print(){
    if(ans<=2){
        for(int i=1;i<=n;i++){
            cout<<a[i]<<' ';
        }
        cout<<endl;
    }
    ans++;
}
void queen(int i){
    if(i==n+1){
        print();
        return;
    }else{
        for(int j=1;j<=n;j++){
            if((b[j]==0)&&(c[i+j]==0)&&(d[i-j+n]==0)){
                a[i]=j;
                b[j]=1;
                c[i+j]=1;
                d[i-j+n]=1;
                queen(i+1);
                b[j]=0;
                c[i+j]=0;
                d[i-j+n]=0;
                
            }
        }
    }
}
int main(){
    cin>>n;
    queen(1);
    cout<<ans;
    return 0;
}

解题思路:

需要设置三个数组来储存列以及两个对角线的占据情况,然后开始一次尝试可能的位置,如果皇后没有占领,执行占据并搜索下一个皇后位置,如果不行就回到上一个皇后的位置。此处输入是需要对总方案数做一个判断,输出前三个方案,但是每一次达到n+1后,方案数都加1.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值