1. 程式人生 > 其它 >第二部分 基礎演算法 --> 第五章 搜尋與回溯演算法

第二部分 基礎演算法 --> 第五章 搜尋與回溯演算法

目錄

搜尋與回溯演算法

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 放蘋果