简单回溯法

简单回溯法

全排列问题

题目描述
请给出N的全排列

输入
输入一个整数N。

N有多个。

输出
输出N的全排列。

样例输入
2
3

样例输出
1 2
2 1

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

#include <iostream>
using namespace std;

int a[20] = {0}, n;
int test(int i, int k) {
    int t = 0;
    for (int j = 1; j <= i-1; j++) {
        if (a[j] == k) {
            t = 1;
            break;
        }
    }
    if (!t) return 1;
    return 0;
}

void try1(int i) {
    if (i == n+1) {
        for (int j = 1; j < n; j++) {
            cout << a[j] << " ";
        }
        cout << a[n] <<"\n";
    } else {
        for (int k = 1; k <= n; k++) {
            if (test(i, k) == 1) {
                a[i] = k;
                try1(i+1);
            }
        }
    }
}

int main() {
    while (cin >> n) {
        try1(1);
        cout << "\n";
    }
    return 0;
}

n皇后问题

题目描述
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

输入
整数n.n小于等于10

输出
输出满足n皇后问题的解的个数

样例输入
4
8
样例输出
2
92

#include <iostream>
using namespace std;

int vis[2][1009] = {0};
int tot = 0;
void search(int cur);
int n;    // 皇后数目
int main() {
    while (cin >> n) {
        tot = 0;
        search(0);
        cout << tot << endl;
    }
    return 0;
}

void search(int cur) {
    if (cur == n) tot++;
    else {
        for (int i  = 0; i < n; i++) {
            if (!vis[0][i] && !vis[1][cur+i] && !vis[2][cur-i+100]) {
                vis[0][i] = vis[1][cur+i] = vis[2][cur-i+100] = 1;
                search(cur+1);
                vis[0][i] = vis[1][cur+i] = vis[2][cur-i+100] = 0;
            }
        }
    }
}

问题 C: 马踏棋盘问题

题目描述
在N*M的棋盘中,马只能走日字,马从(x,y)处出发,把棋盘的每一格都走一次且只走一次,所有路径条数。

输入
输入两个整数M,N,

以及起点位置,x,y(>=0且<=20);

输出
输出路径条数

样例输入
2 3
0 0
样例输出
0

#include <iostream>
#include <queue>
using namespace std;
typedef struct Node {
    int x;
    int y;
    int v;
};
Node path[109][109];
int m, n;           // 棋盘范围
int cnt = 0;        // 统计路线数量
void test() {
    bool judge = true;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (!path[i][j].v) {    // 发现未走过的点, 则不是路径
                judge = false;
            }
        }
    }
    if(judge)cnt++;                 // 全部走过, 路径数 + 1
}

int fx[] = {1, 2, 2, 1, -1, -2, -2, -1};
int fy[] = {2, 1, -1, -2, -2, -1, 1, 2};

queue<Node> myQue;
void bfs(int i, int j) {
    myQue.push(path[i][j]);
    path[i][j].v = 1;
    while (!myQue.empty()) {
        Node front = myQue.front();
        for (int i = 0; i < 8; i++) {
            if (front.x+fx[i] >= 0 && front.x+fx[i] < m &&
                front.y+fy[i] >= 0 && front.y+fy[i] < n )       // 判断是否越界
            {
                if (!path[front.x+fx[i]][front.y+fy[i]].v) {    // 未走过的点
                    myQue.push(path[front.x+fx[i]][front.y+fy[i]]);
                    path[front.x+fx[i]][front.y+fy[i]].v = 1;
                }
            }
        }
        test();         // 判断是否走满棋盘
        myQue.pop();
    }
}

void Clear(int m, int n) {
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            path[i][j].x = i;
            path[i][j].y = j;
            path[i][j].v = 0;
        }
    }
    cnt = 0;        // 计数器置0
}
int main() {
    int x, y;
    while (cin >> m >> n >> x >> y) {
        Clear(m, n);        // 初始化
        bfs(x, y);
        cout << cnt << endl;
    }
    return 0;
}

素数环问题

题目描述
把1~N(N<=20)个数摆成一个环,要求相邻两个数的和是素数。
环的第一个位置应该放1。
输出合法环的个数。

输入
输入一个整数

输出
输出环的个数

样例输入
6
样例输出
2

#include <iostream>

using namespace std;

int is_prime[49] = {0, 0, 2, 3, 0, 5, 0, 7, 0, 0, 0,        // 第一位为0
                    11, 0, 13, 0, 0, 0, 17, 0, 19, 0,
                    0, 0, 23, 0, 0, 0, 0, 0, 29, 0,
                    31, 0, 0, 0, 0, 0, 37, 0, 0, 0};

int n, v[49] = {1, 1, 0}, s[49] = {1, 0}, cnt = 0;          // v数组0和1由题目默认不能访问, s数组由题目第一位放1
void dfs(int cur, int n) {
    if (cur == n && is_prime[s[0] + s[n - 1]]) {
        cnt++;
    } else {
        for (int i = 2; i <= n; i++) {
            if (!v[i] && is_prime[i + s[cur - 1]]) {
                s[cur] = i;
                v[i] = 1;
                dfs(cur + 1, n);
                v[i] = 0;
            }
        }
    }
}

int main() {
    int n;
    while (cin >> n) {
        dfs(1, n);
        cout << cnt << endl;
    }
    return 0;
}

迷宫 回溯

题目描述
从S走到D,恰好走T步,能不能走到?走到输出YES,走不到输出NO,X为墙,不能走。

输入
输入三个整数,M,N,T,表示M行N列的迷宫,T为时间,单位分钟。M,N,T全为零是结束输入。

然后是迷宫,X为墙, .可以走。

输出
输出YES或NO

样例输入
4 4 5
S.X.
..X.
..XD
….
3 4 5
S.X.
..X.
…D
0 0 0
样例输出
NO
YES


#include <iostream>
#include <queue>
#include <cstdio>

using namespace std;

typedef struct Node {
    int x;
    int y;
    int v;
    char c;
};

Node path[59][59];
int xx, yy;
void bfs(int x, int y) {
    queue<Node> myQue;
    path[x][y].v = 1;
    myQue.push(path[x][y]);
    while (!myQue.empty()) {
        Node front = myQue.front();
        // 判断四个方向是否能够入队
        if (!path[front.x+1][front.y].v) {
            path[front.x+1][front.y].v = front.v + 1;
            myQue.push(path[front.x+1][front.y]);
        }
        if (!path[front.x][front.y+1].v) {
            path[front.x][front.y+1].v = front.v + 1;
            myQue.push(path[front.x][front.y+1]);
        }
        if (!path[front.x-1][front.y].v) {
            path[front.x-1][front.y].v = front.v + 1;
            myQue.push(path[front.x-1][front.y]);
        }
        if (!path[front.x][front.y-1].v) {
            path[front.x][front.y-1].v = front.v + 1;
            myQue.push(path[front.x][front.y-1]);
        }
        if (front.c == 'D') {   // 如果该位置为D, 则记录位置并退出
            xx = front.x;
            yy = front.y;
            return;
        }
        myQue.pop();
    }
}

void Clear(int m, int n) {
    for (int i = 0; i <= m + 5; i++)
        for (int j = 0; j <= n + 5; j++) {
            path[i][j].v = 1;
            path[i][j].x = i;
            path[i][j].y = j;
            path[i][j].c = ' ';
        }
}

int main() {
    int m, n, t;
    while (cin >> m >> n >> t) {
        if (m == 0 || n == 0 || t == 0)break;
        Clear(m, n);      // 重置数组
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                cin >> path[i][j].c;
                if (path[i][j].c != 'X') {  // 0可走, 1不可走
                    path[i][j].v = 0;
                }
            }
            getchar();
        }
        bfs(1, 1);
        printf("%s\n", (path[xx][yy].v-1 <= t) ? "YES" : "NO"); // 需要减去起点1
    }
    return 0;
}

迷宫问题

题目描述

小明得到一张迷宫地图,他想从(1,1)出发,找一条最短的到(8,8)的路径。

输入
现输入整数N,表示数据包含N行N列个数。然后输入四个整数,分别表示起点和终点的行列值。

然后是N行N列个数,0表示可以通过,1表示不能通过

输出
最短要走几步

样例输入
8
1 1 8 8
0 0 0 0 0 0 0 0
0 1 1 1 1 0 1 0
0 0 0 0 1 0 1 0
0 1 0 0 0 0 1 0
0 1 0 1 1 0 1 0
0 1 0 0 0 0 1 1
0 1 0 0 1 0 0 0
0 1 1 1 1 1 1 0
样例输出
14

#include <iostream>
#include <queue>
using namespace std;

typedef struct Node {
    int x;
    int y;
    int v;
};

Node path[59][59];
void bfs(int x, int y) {
    queue<Node> myQue;
    path[x][y].v = 1;
    myQue.push(path[x][y]);
    while (!myQue.empty()) {
        Node front = myQue.front();
        if (!path[front.x+1][front.y].v) {
            path[front.x+1][front.y].v = front.v + 1;
            myQue.push(path[front.x+1][front.y]);
        }
        if (!path[front.x][front.y+1].v) {
            path[front.x][front.y+1].v = front.v + 1;
            myQue.push(path[front.x][front.y+1]);
        }
        myQue.pop();
    }
}

void Clear(int n) {
    for (int i = 0; i <= n + 5; i++)
        for (int j = 0; j <= n + 5; j++) {
            path[i][j].v = 1;
            path[i][j].x = i;
            path[i][j].y = j;
        }
}

int main() {
    int n, x1, y1, x2, y2;
    while (cin >> n) {
        Clear(n);      // 重置数组
        cin >> x1 >> y1 >> x2 >> y2;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) {
                cin >> path[i][j].v;
            }
        bfs(x1, y1);
        for (int ii = 1; ii <= n; ii++){
            for (int jj = 1; jj <= n; jj++) {
                cout << path[ii][jj].v << " ";
            }
            cout << endl;
        }
        cout << path[x2][y2].v - 1 << endl;     // 起点不算, 需减掉
    }
    return 0;
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值