第二部分 基础算法 --> 第五章 搜索与回溯算法

搜索与回溯算法

1317 【例5.2】组合的输出

【题目描述】
排列与组合是常用的数学方法,其中组合就是从 n 个元素中抽出 r 个元素(不分顺序且 r ≤n),
我们可以简单地将 n 个元素理解为自然数 1,2,…,n,从中任取 r 个数。
现要求你用递归的方法输出所有组合。

【输入】一行两个自然数 n、r(1<n<21,1≤r≤n)。
【输出】所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,
每个元素占三个字符的位置,所有的组合也按字典顺序。

【输入样例】

5 3

【输出样例】

  1  2  3
  1  2  4
  1  2  5
  1  3  4
  1  3  5
  1  4  5
  2  3  4
  2  3  5
  2  4  5
  3  4  5

【参考程序】

#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
int a[N], vis[N], n, r;

//第 m 个数
void dfs(int m){
    if(m>r){
        for(int i=1; i<=r; i++){
            cout<<setw(3)<<a[i];
        }cout<<endl;
        return;
    }
    for(int i=1; i<=n; i++){
        if(vis[i]==0 && a[m-1]<i){
            vis[i]=1;
            a[m] = i;
            dfs(m+1);
            vis[i] = 0;
        }
    }
}
int main(){
    cin>>n>>r;
    dfs(1);
    return 0;
}

1318 【例5.3】自然数的拆分

【题目描述】任何一个大于 1 的自然数 n,总可以拆分成若干个小于 n 的自然数之和。
【输入】输入n。
【输出】按字典序输出具体的方案。

【输入样例】

7

【输出样例】

7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4

【参考程序】

#include<bits/stdc++.h>
using namespace std;
int n,total=0;
const int N=1e3;
int a[N];

//现有和, 选择第 m 个数
void dfs(int sum, int m) {
    if(sum>n) return;
    if(sum==n && m>2) {
        cout<<n<<"=";
        for(int i=1; i<m-1; i++) {
            cout<<a[i]<<"+";
        }
        cout<<a[m-1]<<endl;
        return ;
    }
    for(int i=1; i<=n; i++) {
        if(sum+i<=n && a[m-1]<=i) {
            a[m] = i;
            dfs(sum+i, m+1);
            a[m] = 0;
        }
    }
}
int main() {
    cin>>n;
    dfs(0,1);
    return 0;
}

1212 LETTERS

【题目描述】
给出一个 roe×col 的大写字母矩阵,一开始的位置为左上角,
你可以向上下左右四个方向移动,并且不能移向曾经经过的字母。
问最多可以经过几个字母。

【输入】第一行,输入字母矩阵行数 R 和列数 S,1≤R,S≤20。
接着输出 R行 S列字母矩阵。

【输出】最多能走过的不同字母的个数。

【输入样例】

3 6
HFDFFB
AJHGDH
DGAGEH

【输出样例】

6

【参考程序】

#include <bits/stdc++.h>
using namespace std;
char a[24][24];//这个用于存储输入的字符
bool po[30];//26个字母,用以判断此字母是否被读过了
int maxl;//存储最大值
int pa[4] = { 1,0,-1,0 };//控制x走向
int pb[4] = { 0,1,0,-1 };//控制y走向
int n, m;
void f(int x1, int y1, int seft) { //x1代表此时横坐标,y1代表此时纵坐标,seft代表 此时 不同字母的个数
    if(seft>maxl) maxl=seft;//如果当前值大过最高值,则更新最高值
    int x, y;
    for (int i=0; i<=3; i++) {
        //有四种方案,分别对应上下左右
        x = x1+pa[i];
        y = y1+pb[i];

        //可行性方案,首先确保移动后的点在方格内,其次,这个点存储的字母未被使用过
        if (x>=1 && x<=n && y>=1 && y<=m && (!po[a[x][y]-'A'])) {
            po[a[x][y]-'A'] = 1;//标记
            f(x, y, seft+1);//递归
            po[a[x][y]-'A'] = 0;//解除标记
        }
    }
}
int main() {
    cin>>n>>m;
    for (int i=1; i<=n; i++){
        for (int j=1; j<=m; j++){
            cin>>a[i][j];
        }
    }
    po[a[1][1]-65] = 1;
    f(1, 1, 1);//从第一个点开始即可
    cout << maxl;
    return 0;
}

1213 八皇后问题

【题目描述】在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。
【输入】(无)
【输出】按给定顺序和格式输出所有八皇后问题的解(见样例)。
【输入样例】(无)
【输出样例】

No. 1
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
No. 2
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 1 0 0 0 0 0
...以下省略

【参考程序】

#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
int a[N],b[N],c[N],d[N],n,cnt=0;

// a[j]=i;    //第i行第j列放置
// b[j]=1;    //第j列已经放置
// c[i+j]=1;  //对角线(右上角到左下角)已放置
// d[i-j+n]=1;//对角线(左上角到右下角)已放置
// 每行/列一个皇后,也就是 第i行/列是第 i个皇后
//放置第 k 个皇后
void dfs(int i){
    if(i>n){
        cnt++;
        cout<<"No. "<<cnt<<endl;
       for(int k=1;k<=n; k++) {
           for(int j=1; j<=n; j++){
               if(a[k]==j) cout<<1<<" ";
               else cout<<0<<" ";
           }cout<<endl;
       }
       return ;
    }
    for(int j=1; j<=n; j++){
        if(b[j]==0 && c[i+j]==0 && d[i-j+n]==0){
            a[j]=i, b[j]=1, c[i+j]=1, d[i-j+n]=1;
            dfs(i+1);
            b[j]=0, c[i+j]=0, d[i-j+n]=0;
        }
    }
}
int main(){
    n=8; //cin>>n;
    dfs(1);
    return 0;
}

1214:八皇后

【题目描述】
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。

如何将 8 个皇后放在棋盘上(有 8 ×8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。

对于某个满足要求的8皇后的摆放方法,定义一个皇后串 a 与之对应,即 a=b1b2...b8,

其中 bi 为相应摆法中第 i 行皇后所处的列数。

已经知道 8 皇后问题一共有 92 组解(即 92 个不同的皇后串)。

给出一个数 b,要求输出第 b 个串。

串的比较是这样的:皇后串 x 置于皇后串 y 之前,当且仅当将 x 视为整数时比 y 小。

【输入】第 1 行是测试数据的组数n,后面跟着n行输入。
每组测试数据占1行,包括一个正整数b(1≤b≤92)。

【输出】输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。

【输入样例】

2
1
92

【输出样例】

15863724
84136275

【参考程序】

#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
int a[N],b[N],c[N],d[N], n, cnt=0;
int data[N][N];

// a[j]=i;    //第i行第j列放置
// b[j]=1;    //第j列已经放置
// c[i+j]=1;  //对角线(右上角到左下角)已放置
// d[i-j+n]=1;//对角线(左上角到右下角)已放置
// 每行/列一个皇后,也就是 第i行/列是第 i个皇后
//每一列一个皇后
void dfs(int j){
    if(j>n){
        cnt++;
        for(int i=1; i<=n; i++){
            data[cnt][i]=a[i];
        }
    }
    for(int i=1; i<=n; i++){
        if(b[i]==0 && c[i+j]==0 &&d[i-j+n]==0){
            a[j]=i, b[i]=1, c[i+j]=1, d[i-j+n]=1;
            dfs(j+1);
            b[i]=0, c[i+j]=0, d[i-j+n]=0;
        }
    }
}
int main(){
    n=8; 
    dfs(1);
    int num; cin>>num;
    for(int i=1; i<=num; i++){
        int b; cin>>b;
        for(int j=1; j<=n; j++){
            cout<<data[b][j];
        }cout<<endl;
    }
    return 0;
}

1215 迷宫

1216 红与黑

1217 棋盘问题

1218 取石子游戏

1219 马走日

【参考程序】

#include<iostream>
#include<cstring>
using namespace std;
const int N=10;
int a[N][N];
int dis[][2]={-2,-1, -1,-2, 1,-2, 2,-1, 2,1, 1,2, -1,2, -2,1};
int n,m,sx,sy,ans;

void pr(){
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            cout<<a[i][j]<<" ";
        }cout<<endl;
    }cout<<endl;
}
//遍历数量,将要遍历的点 
void dfs(int cnt,int x,int y){
//    if(cnt<4) pr();
    if(cnt==n*m) {
        ans++; return;
    } 
    for(int i=0; i<8; i++){
        int tx=x+dis[i][0];
        int ty=y+dis[i][1];
        if(tx<0||tx>=n||ty<0||ty>=m) continue;
        if(a[tx][ty]==0){
            a[tx][ty]=1;
            dfs(cnt+1,tx,ty);
            a[tx][ty]=0;
        }
    }
}

int main(){
//    freopen("data.in", "r", stdin);
    int t; cin>>t;
    while(t--){
        cin>>n>>m>>sx>>sy;
        ans=0;
        memset(a, 0, sizeof(a));
        a[sx][sy]=1;
        dfs(1,sx,sy);
        cout<<ans<<endl;
    }
    return 0;
}

1220 单词接龙

1221 分成互质组

1222 放苹果

posted @ 2022-03-23 13:35  HelloHeBin  阅读(203)  评论(0)    收藏  举报