《挑战程序设计竞赛》第二章-最基础的“穷竭搜索”-习题

深度优先搜索

POJ-1979 Red and Black

从字符为 ‘@’ 的格子开始向 ‘.’ 的格子搜索,输出与之连通的 ‘.’ 的格子有多少个,包括 ‘@’ 在内。

1、DFS 内直接计数,能进入这个 DFS 的均是合法位置
2、为已经访问过的格子做标记,将原来的 ‘.’ 可达变为 ‘#’ 不可达
3、朝四个方向分别进行判断,位置合法:不超出范围、字符为 ‘.’,则进入

#include <iostream>
using namespace std;
const int maxn = 25;
char maze[maxn][maxn];
int n, m, sx, sy, cnt;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
void dfs(int x, int y) {
    cnt++;
    maze[x][y] = '#';
    for (int i = 0; i < 4; ++i) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx >= 0 && nx < n && ny >= 0 && ny < m && maze[nx][ny] == '.')
            dfs(nx, ny);
    }
}
int main() {
    ios::sync_with_stdio(false);
    while (cin >> m >> n && n && m) {
        cnt = 0;
        for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) {
            cin >> maze[i][j];
            if (maze[i][j] == '@') sx = i, sy = j;
        }
        dfs(sx, sy);
        cout << cnt << endl;
    }
    return 0;
}
AOJ-0118 Property Distribution

统计有多少联通快,这里联通块指相邻的方格中的字符是相等的。注意,图中有多种字符连通块。

1、由于有多种字符,故相比于 POJ-1979,DFS 增加了一个 char 类型的参数,避免将字符写死
2、只要是没有被访问过的字符,且字符等于当前 DFS 访问的字符 (char 参数),即进入递归过程

#include <iostream>
using namespace std;
const int maxn = 100 + 5;
char maze[maxn][maxn];
int h, w;
const int dx[4] = {0, -1, 0, 1};
const int dy[4] = {1, 0, -1, 0};
void dfs(int x, int y, char c) {
    maze[x][y] = 'V';
    for (int i = 0; i < 4; ++i) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx >= 0 && nx < h && ny >= 0 && ny < w && c == maze[nx][ny])
            dfs(nx, ny, c);
    }
}
int main() {
    ios::sync_with_stdio(false);
    while (cin >> h >> w && h && w) {
        int ans = 0;
        for (int i = 0; i < h; ++i) 
            for (int j = 0; j < w; ++j)
                cin >> maze[i][j];
        for (int i = 0; i < h; ++i) {
            for (int j = 0; j < w; ++j) {
                if (maze[i][j] != 'V') {
                    dfs(i, j, maze[i][j]);
                    ans++;
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}
AOJ-0033 BALL

给定一个序列,长度为定长 10 10 ,问是否可以将此序列分为两个子序列,保证两个子序列均是递增的,子序列可以不连续。

1、子集枚举或者递归均可
2、子集枚举使用二进制判断,对从 1~1024 的每个整形表达的二进制形态判断,取 0 和 1 的两个子集是否有序
3、递归则分为两种情况,选取和不选取。在递归的结束分别判断选取和不取的情况是否符合要求
4、此问题类似于背包问题,背包问题是最优化问题,而此问题是存在问题。若要用动态规划解决此问题,首先应该将存在问题转化为最优化问题

// 子集枚举版
#include <bitset>
#include <iostream>
using namespace std;
int T;
const int maxn = 10;
int ball[maxn];
int main() {
    ios::sync_with_stdio(false);
    cin >> T; while (T--) {
        for (int i = 0; i < maxn; ++i) cin >> ball[i];
        bitset<10> bs;
        int all = 1024;
        while (all--) {
            bs = static_cast<bitset<10>>(all);
            bool perfect = true;
            int left = 0, right = 0;
            for (int i = 0; i < 10; ++i) {
                if (bs[i]) {
                    if (ball[i] > left) left = ball[i];
                    else {
                        perfect = false; break;
                    }
                }
                else {
                    if (ball[i] > right) right = ball[i];
                    else {
                        perfect = false;
                        break;
                    }
                }
            }
            if (perfect) break;
        }
        if (all >= 0) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}
POJ-3009 Curling 2.0

广度优先搜索

AOJ-0558 Cheese
POJ-3669 Meteor Shower

参考了CSDN-Keaper大佬的博客,他的代码简洁漂亮值得学习。

BFS 搜索,找到一个永远不会被破坏的格点,并求出到这个格点的最短距离。所谓破坏,即第 t 秒钟会在 x,y 处出现陨石,将这个点及其周围的四个点同时摧毁,被摧毁的格点不可再通过,但在被摧毁之前可以通过。

1、以 a[i][j] 记录 i, j 最早被摧毁的时刻,d[i][j] 记录最早可以到达 i, j 的时间
2、使用 BFS 拓展可到达的区域。若该区域早已经被损毁,则不再走此区域;若该区域未被摧毁,且未被访问(因为如果被访问过则一定比当前这次访问更早,再访问该点也就没有意义了),则加入队列访问
3、直到找到一个历史上和未来均不会被毁灭的格点,该格点即安全区域,停止搜索

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAX = 300 + 10;
const int INF = 0x3f3f3f3f;
int a[MAX][MAX], d[MAX][MAX];
int dx[4] = { 0, 1, 0, -1 };
int dy[4] = { 1, 0, -1, 0 };
typedef pair<int, int> P;
typedef long long ll;
int bfs() {
    if (a[0][0] == 0) return -1;
    memset(d, 0x3f, sizeof(d));
    queue<P> que;
    que.push(P(0, 0));
    d[0][0] = 0;
    while (!que.empty()) {
        int x = que.front().first;
        int y = que.front().second;
        que.pop();
        if (a[x][y] == INF) {
            return d[x][y];
            break;
        }
        for (int i = 0; i < 4; ++i) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx >= 0 && ny >= 0 && a[nx][ny] > d[x][y] + 1 && d[nx][ny] == INF) {
                d[nx][ny] = d[x][y] + 1;
                que.push(P(nx, ny));
            }
        }
    }
    if (que.empty()) return -1;
}
int main() {
    int m;
    while (scanf("%d", &m) != EOF) {
        memset(a, 0x3f, sizeof(a));
        for (int i = 0; i < m; ++i) {
            int x, y, t;
            scanf("%d%d%d", &x, &y, &t);
            a[x][y] = min(a[x][y], t);
            for (int j = 0; j < 4; ++j) {
                int nx = x + dx[j];
                int ny = y + dy[j];
                if (nx >= 0 && ny >= 0) {
                    a[nx][ny] = min(a[nx][ny], t);
                }
            }
        }
        int ans = bfs();
        printf("%d\n", ans);
    }
    return 0;
}
AOJ-0121 Seven Puzzle

穷竭搜索

POJ-2718 Smallest Difference
POJ-3187 Backward Digit Sums
POJ-3050 Hopscotch
AOJ-0525 Osenbei
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值