【算法1-7】搜索

842. 排列数字(dfs)

#include <iostream>
using namespace std;
const int N = 10;

int n, path[N];

void dfs(int u, int state) {
    if (u == n) {
        for (int i = 0; i < u; ++ i) {
            cout << path[i] << ' ';
        }
        cout << endl;
        return ;
    }
    for (int i = 1; i <= n; ++ i) {
        if (!(state >> i & 1)) {
            path[u] = i;
            dfs(u + 1, state + (1 << i));
        }
    }
}

int main() {
    cin >> n;
    dfs(0, 0);
}

843. n-皇后问题(dfs)

  • n* n放n个,因此一行放一个,dfs每一行中在哪个位置放皇后
  • O ( N ! ) O(N!) O(N!)
  • 关于对角线和斜对角线:显然由行和列可以得到一一对应的对角线,因此,可以推出公式 y = x + b y=x+b y=x+b y = − x + b y=-x+b y=x+b,因此得到 b = y − x b=y-x b=yx b = x + y b=x+y b=x+y,由于y-x(数组下标)可能是负数,因此加一个偏移量n防止下标小于0
  • 注意数组大小要开两倍,因为对角线数量是横纵的两倍
#include <iostream>
using namespace std;
const int N = 20;

int n;
char g[N][N];
bool col[N], dg[N], udg[N];

void dfs(int x) {
    if (x == n) {
        for (int i = 0; i < n; ++ i) {
            puts(g[i]);
        }
        puts("");
        return ;
    }
    for (int y = 0; y < n; ++ y) {
        if (!col[y] && !dg[y - x + n] && !udg[x + y]) {
            col[y] = dg[y - x + n] = udg[x + y] = true;
            g[x][y] = 'Q';
            dfs(x + 1);
            col[y] = dg[y - x + n] = udg[x + y] = false;
            g[x][y] = '.';
        }
    }
}

int main() {
    cin >> n;
    for (int i = 0; i < n; ++ i)
        for (int j = 0; j < n; ++ j)
            g[i][j] = '.';
    dfs(0);
}

844. 走迷宫(bfs)

#include <iostream>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 110;

struct Node {
    int x, y, dist;
};

int n, m;
char g[N][N];
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};

int bfs() {
    queue<Node> que;
    que.push({1, 1, 0});
    g[1][1] = '1';
    while (que.size()) {
        auto t = que.front();
        que.pop();
        if (t.x == n && t.y == m) {
            return t.dist;
        }
        for (int i = 0; i < 4; ++ i) {
            int nx = t.x + dx[i], ny = t.y + dy[i];
            if (nx < 1 || nx > n || ny < 1 || ny > m || g[nx][ny] == '1') continue;
            g[nx][ny] = '1';
            que.push({nx, ny, t.dist + 1});
        }
    }
    return -1;
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= m; ++ j)
            cin >> g[i][j];
    cout << bfs();
}

845. 八数码(bfs)

  • 由于确定为3 * 3,给出所有数,可以得出它在方格中的位置为(k / 3, k % 3),而可以由 3 ∗ x + y 3 * x + y 3x+y由方格得到所有数中的位置。因此,可以先将x的所有数中坐标转换为方格中坐标,上下左右移动再转回方格中坐标
  • “得到正确排列至少需要进行多少次交换“,已知初始状态和最终状态,求最少步数,bfs
  • 这里用一个map来维护string的dist值,注意用!dist.count(s)来表示当前的s状态是第一次走到的,可以被放入queue和更新dist值,否则不更新不放入
#include <iostream>
#include <queue>
#include <unordered_map>
using namespace std;

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};

int bfs(string state) {
    queue<string> que;
    unordered_map<string, int> dist;
    que.push(state);
    dist[state] = 0;
    
    string end = "12345678x";
    while (que.size()) {
        string s = que.front();
        que.pop();
        if (s == end) {
            return dist[s];
        }
        int k = s.find('x');
        int tmpd = dist[s];
        int x = k / 3, y = k % 3;
        for (int i = 0; i < 4; ++ i) {
            int nx = x + dx[i], ny = y + dy[i];
            if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) {
                int now = nx * 3 + ny;
                swap(s[k], s[now]);
                if (!dist.count(s)) {
                    que.push(s);
                    dist[s] = tmpd + 1;
                }
                swap(s[k], s[now]);
            }
        }
    }
    return -1;
}

int main() {
    string state = "";
    for (int i = 0; i < 9; ++ i) {
        char ch;
        cin >> ch;
        state += ch;
    }
    cout << bfs(state);
}

846. 树的重心

  • ans为全局答案,是 剩余连通块中点数最大值的最小值;因此,我们每dfs到一个点假设当前这个点为重心时,size维护当前剩余连通块中点数的最大值,分别枚举这个点的儿子节点,以及儿子节点的和,用总节点数减去儿子节点的和就是父节点那边的连通块点数
  • 用st数组避免枚举父节点,只枚举子节点
  • dfs函数的返回值为包括当前这个点在内这个连通块的点数
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e5 + 10;

int n;
vector<int> g[N];
bool st[N];
int ans = 1e9;

int dfs(int u) {
    st[u] = true;
    int size = 0, sum = 0;
    for (int i = 0; i < g[u].size(); ++ i) {
        int j = g[u][i];
        if (st[j]) continue;
        st[j] = true;
        int s = dfs(j);
        size = max(size, s);
        sum += s;
    }
    size = max(size, n - 1 - sum);
    ans = min(ans, size);
    return sum + 1;
}

int main() {
    cin >> n;
    for (int i = 0; i < n - 1; ++ i) {
        int a, b;
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1);
    cout << ans;
}

847. 图中点的层次

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;

int n, m;
vector<int> g[N];
int dist[N];

int bfs() {
    memset(dist, -1, sizeof dist);
    queue<int> que;
    que.push(1);
    dist[1] = 0;
    while (que.size()) {
        auto t = que.front();
        que.pop();
        if (t == n) {
            return dist[t];
        }
        for (int i = 0; i < g[t].size(); ++ i) {
            int j = g[t][i];
            if (dist[j] != -1) continue;
            dist[j] = dist[t] + 1;
            que.push(j);
        }
    }
    return -1;
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++ i) {
        int a, b;
        cin >> a >> b;
        g[a].push_back(b);
    }
    cout << bfs();
}

P1219 [USACO1.5]八皇后 Checker Challenge

#include <iostream>
using namespace std;
const int N = 50;

int n;
int cnt;
int col[N], dg[N], udg[N];
int ans[N];

void dfs(int u) {
    if (u == n + 1) {
        cnt ++ ;
        if (cnt <= 3) {
            for (int i = 1; i <= n; ++ i)
                cout << ans[i] << ' ';
            cout << endl;
        }
        return ;
    }
    for (int i = 1; i <= n; ++ i) {
        if (!col[i] && !dg[i - u + n] && !udg[i + u]) {
            col[i] = dg[i - u + n] = udg[i + u] = true;
            ans[u] = i;
            dfs(u + 1);
//            ans[u] = 0;
            col[i] = dg[i - u + n] = udg[i + u] = false;
        }
    }
}

int main() {
    cin >> n;
    dfs(1);
    cout << cnt;
}

P2392 kkksc03考前临时抱佛脚

  • 每项作业之间是独立的,考虑一项作业,总时间是左右两边时间中的最大值,因此要总时间最少,左右两边时间要尽可能靠近所有时间的一半。
  • 想到了背包,保证比t/2小,又要取到的价值尽可能大,一个物品只有两种状态,转换为一个价值和花费相等的01背包问题,背包大小为t/2
  • 假设求得背包的最大价值为v,显然另一个脑耗时为t-v,总时间为max(v, t- v)
#include <iostream>
using namespace std;
const int N = 20 * 60 + 10;

int a[5], b[25];
int f[N];

int main() {
    for (int _ = 1; _ <= 4; ++ _) {
        cin >> a[_];
    }
    int ans = 0;
    for (int _ = 1; _ <= 4; ++ _) {
        int sum = 0;
        for (int i = 1; i <= a[_]; ++ i) {
            cin >> b[i];
            sum += b[i];
        }
        for (int i = 1; i <= a[_]; ++ i) {
            for (int j = sum / 2; j >= b[i]; -- j) {
                f[j] = max(f[j], f[j - b[i]] + b[i]);
            }
        }
        ans += sum - f[sum / 2];
        for (int i = 0; i <= sum / 2; ++ i) {
            f[i] = 0;
        }
    }
    cout << ans;
}

  • 数据范围只有20,可以搜索
#include <iostream>
using namespace std;

int a[5];
int b[5][25];

int mx, Left, Right;

void dfs(int home, int u) {
    if (u > a[home]) {
        mx = min(mx, max(Left, Right));
        return ;
    }
    Left += b[home][u];
    dfs(home, u + 1);
    Left -= b[home][u];
    Right += b[home][u];
    dfs(home, u + 1);
    Right -= b[home][u];
}

int main() {
    for (int i = 1; i <= 4; ++ i) {
        cin >> a[i];
    }
    for (int i = 1; i <= 4; ++ i) {
        for (int j = 1; j <= a[i]; ++ j) {
            cin >> b[i][j];
        }
    }
    int ans = 0;
    for (int i = 1; i <= 4; ++ i) {
        mx = 1e9;
        Left = Right = 0;
        dfs(i, 1);
        ans += mx;
    }
    cout << ans;
}

P1443 马的遍历

  • “左对齐,宽 5 格,不能到达则输出 -1” printf("%-5d", dist[i][j]);
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 410;
typedef pair<int, int> PII;

int n, m, x, y;
int dx[] = {-2, -2, -1, 1, 2, 2, 1, -1};
int dy[] = {-1, 1, 2, 2, 1, -1, -2, -2};
int dist[N][N];

void bfs() {
    memset(dist, -1, sizeof dist);
    queue<PII> que;
    que.push({x, y});
    dist[x][y] = 0;
    while (que.size()) {
        auto t = que.front();
        que.pop();
        for (int i = 0; i < 8; ++ i) {
            int nx = t.first + dx[i], ny = t.second + dy[i];
            if (nx < 1 || nx > n || ny < 1 || ny > m || dist[nx][ny] != -1) continue;
            que.push({nx, ny});
            dist[nx][ny] = dist[t.first][t.second] + 1;
        }
    }
}

int main() {
    cin >> n >> m >> x >> y;
    bfs();
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= m; ++ j) {
            printf("%-5d", dist[i][j]);
        }
        cout << endl;
    }
}

P1135 奇怪的电梯

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 210;

int n, x, y;
int a[N];
bool st[N];
int dist[N];

int bfs() {
    queue<int> que;
    memset(dist, -1, sizeof dist);
    que.push(x);
    dist[x] = 0;
    while (que.size()) {
        auto t = que.front();
        que.pop();
        if (t == y) {
            return dist[t];
        }
        int up = t + a[t];
        if (up >= 1 && up <= n && dist[up] == -1) {
            que.push(up);
            dist[up] = dist[t] + 1;
        }
        int down = t - a[t];
        if (down >= 1 && down <= n && dist[down] == -1) {
            que.push(down);
            dist[down] = dist[t] + 1;
        }
    }
    return -1;
}

int main() {
    cin >> n >> x >> y;
    for (int i = 1; i <= n; ++ i) {
        cin >> a[i];
    }
    cout << bfs();
}

P2895 [USACO08FEB]Meteor Shower S

  • 首先根据题目所给的所有陨石,将所有会被砸到的陨石标记,地图中所有点代表这个点被陨石砸到的时间,如果不会被砸到设置为1010(大于时间上限)
  • 最短时间,就是bfs,只要搜到一个点砸到时间为1010,说明这个点是安全的,退出bfs
  • 更新队列时,不仅不能出第一象限,不能被走过,还需要这个点在这个时间之前没有被砸过
  • 注意这道题可以走到300以外
  • 注意陨石下落时间以最早的为准!!!
#include <iostream>
#include <queue>
using namespace std;
const int N = 510;
typedef pair<int, int> PII;

int n;
int g[N][N];
bool st[N][N];
int dist[N][N];

int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};

int bfs() {
    queue<PII> que;
    que.push({0, 0});
    st[0][0] = true;
    dist[0][0] = 0;
    while (que.size()) {
        auto t = que.front();
        que.pop();
        int x = t.first, y = t.second;
        if (g[x][y] == 1010) {
            return dist[x][y];
        }
        for (int i = 0; i < 4; ++ i) {
            int nx = x + dx[i], ny = y + dy[i];
            if (nx >= 0 && ny >= 0 && !st[nx][ny] && (g[nx][ny] > (dist[x][y] + 1))) {
                que.push({nx, ny});
                st[nx][ny] = true;
                dist[nx][ny] = dist[x][y] + 1;
            }
        }
    }
    return -1;
}

int main() {
    cin >> n;
    for (int i = 0; i < N; ++ i) {
        for (int j = 0; j < N; ++ j) {
            g[i][j] = 1010;
        }
    }
    for (int i = 0; i < n; ++ i) {
        int x, y, t;
        cin >> x >> y >> t;
        g[x][y] = min(g[x][y], t);
        for (int j = 0; j < 4; ++ j) {
            int nx = x + dx[j], ny = y + dy[j];
            if (nx >= 0 && ny >= 0) {
                g[nx][ny] = min(g[nx][ny], t);
            }
        }
    }
    cout << bfs();
}

P1036 [NOIP2002 普及组] 选数

#include <iostream>
using namespace std;
const int N = 25;

int n, k;
int a[N];
int ans;

bool check(int x) {
    if (x == 1) return false;
    for (int i = 2; i * i <= x; ++ i) {
        if (x % i == 0) {
            return false;
        }
    }
    return true;
}

void dfs(int u, int sum, int now) {
    if (u == n + 1) {
        if (now == k && check(sum)) {
            ans ++ ;
        }
        return ;
    }
    dfs(u + 1, sum + a[u], now + 1);
    dfs(u + 1, sum, now);
}

int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; ++ i) {
        cin >> a[i];
    }
    dfs(1, 0, 0);
    cout << ans;
}

P2036 [COCI2008-2009#2] PERKET

#include <iostream>
using namespace std;
const int N = 15;

int n;
int a[N], b[N];
int ans = 2e9 + 1;

void dfs(int u, int suan, int ku, int cnt) {
    if (u == n + 1) {
        if (cnt) {
            ans = min(ans, abs(suan - ku));
        }
        return ;
    }
    dfs(u + 1, suan * a[u], ku + b[u], cnt + 1);
    dfs(u + 1, suan, ku, cnt);
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; ++ i) {
        cin >> a[i] >> b[i];
    }
    dfs(1, 1, 0, 0);
    cout << ans;
}

P1433 吃奶酪(状压dp)

1.搜索

简单介绍一下搜索的技巧之一:卡时。

什么时候可以用到卡时呢?

当求最优解(max,min)(max,min)时,数据范围较大(但是如果过大那就别想了),我们可以贪心的卡时一下。

总的来说,卡时就是不断的试我们认为的最优解,次优解,最终找出真正的最优解。

就这道题来说,我们可以贪心的每次找离目前点最近的点次近的点,以达到找到的解中在规定时限内出现最优解的情况。

看到这里可能会很笼统,好吧,其实就是在朴素的搜索里加一个特判,如果我们发现即将要超时,那么直接输出我们找到过的最优解

3e7和940

记录每条边的终点和长度

#include <iostream>
#include <cmath>
#include <algorithm>
#include <ctime>
using namespace std;
const int N = 17;

struct Node {
    double dist;
    int ed;
    
    bool operator< (const Node &w) const {
        return dist < w.dist;
    }
};

int n;
double x[N], y[N];
Node a[N][N];
bool st[N];
double ans = 1e10;
int l;

void dfs(int u, double sum, int cnt) {
    l ++ ;
    if (l >= 30000000) {
        int t = clock();
        if (t >= 940) {
            printf("%.2lf", ans);
            exit(0);
        }
    }
    if (sum >= ans) return ;
    if (cnt == n) {
        ans = min(ans, sum);
        return ;
    }
    for (int i = 1; i <= n; ++ i) {
        if (st[a[u][i].ed] || u == a[u][i].ed) continue;
        st[a[u][i].ed] = true;
        dfs(a[u][i].ed, sum + a[u][i].dist, cnt + 1);
        st[a[u][i].ed] = false;
    }
}

int main() {
    cin >> n;
    n ++ ;
    x[1] = 0, y[1] = 0;
    for (int i = 2; i <= n; ++ i) {
        cin >> x[i] >> y[i];
    }
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            a[i][j].dist = sqrt(((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])));
            a[i][j].ed = j;
        }
        sort(a[i] + 1, a[i] + n + 1);
    }
    st[1] = true;
    dfs(1, 0, 1);
    printf("%.2lf", ans);
}

2.状压dp
设f[i][s]表示从i点出发遍历集合为s的点的路程最小值(i也包括在s里),枚举s里的其他点进行转移。

边界为f[i][s]=0(s中只有i)。

注意最后答案要加上到(0,0)的距离。

时间复杂度O(n*2^n)

memset 127 表示int上限,double数组也可以这样赋值

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 17;

int n;
double x[N], y[N];
double f[N][1 << 18];

double calc(int a, int b) {
    return sqrt((x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]));
}

int main() {
    cin >> n;
    for (int i = 0; i < n; ++ i) {
        cin >> x[i] >> y[i];
    }
    memset(f, 127, sizeof f);
    for (int s = 0; s < (1 << n); ++ s) {
        for (int i = 0; i < n; ++ i) {
            if (!(s >> i & 1)) continue;
            if (s == (1 << i)) {
                f[i][s] = 0;
                continue;
            }
            for (int j = 0; j < n; ++ j) {
                if (i == j) continue;
                if (!(s >> j & 1)) continue;
                f[i][s] = min(f[i][s], f[j][s - (1 << i)] + calc(i, j));
            }
        }
    }
    double ans = -1;
    for (int i = 0; i < n; ++ i) {
        double now = f[i][(1 << n) - 1] + sqrt(x[i] * x[i] + y[i] * y[i]);
        if (ans == -1 || now < ans) {
            ans = now;
        }
    }
    printf("%.2lf", ans);
}

P1605 迷宫

#include <iostream>
using namespace std;
const int N = 10;

int n, m, t;
int g[N][N];
int sx, sy, ex, ey;
int ans;
bool st[N][N];

int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};

void dfs(int x, int y) {
    if (x == ex && y == ey) {
        ans ++ ;
        return ;
    }
    for (int i = 0; i < 4; ++ i) {
        int nx = x + dx[i], ny = y + dy[i];
        if (nx < 1 || nx > n || ny < 1 || ny > m || st[nx][ny] || g[nx][ny]) continue;
        st[nx][ny] = 1;
        dfs(nx, ny);
        st[nx][ny] = 0;
    }
}

int main() {
    cin >> n >> m >> t;
    cin >> sx >> sy >> ex >> ey;
    for (int i = 0; i < t; ++ i) {
        int x, y;
        cin >> x >> y;
        g[x][y] = 1;
    }
    st[sx][sy] = 1;
    dfs(sx, sy);
    cout << ans;
}

P1019 [NOIP2000 提高组] 单词接龙

两个单词合并时,合并部分取的是最小重叠部分

相邻的两部分不能存在包含关系就是说如果存在包含关系,就不能标记为使用过。

每个单词最多出现两次.

首先是预处理,用coin[i][j]来存储 第i个单词 后连接 第j个单词 的 最小重叠部分

#include <iostream>
using namespace std;
const int N = 25;

int n;
string tr[N];
int st[N];  // 字符串被使用的次数
int coin[N][N]; // 第一个字符串后面接第二个字符串的最小重叠部分
int ans, now;

int calc_coin(int a, int b) {
    bool ok = true;
    for (int k = (int)tr[a].size() - 1; k >= 0; -- k) {
        ok = true;
        for (int i = k, j = 0; i < tr[a].size(); ++ i, ++ j) {
            if (j >= tr[b].size() || tr[a][i] != tr[b][j]) {
                ok = false;
                break;
            }
        }
        if (ok) {
            return (int)tr[a].size() - 1 - k + 1;
        }
    }
    return 0;
}
void dfs(int i) {
    ans = max(now, ans);
    for (int j = 1; j <= n; ++ j) {
        if (st[j] >= 2) continue;
        if (coin[i][j] == 0) continue;
        if (coin[i][j] == tr[i].size() || coin[i][j] == tr[j].size()) continue;
        st[j] ++ ;
        now += (tr[j].size() - coin[i][j]);
        dfs(j);
        st[j] -- ;
        now -= (tr[j].size() - coin[i][j]);
    }
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; ++ i) {
        cin >> tr[i];
    }
    char ch;
    cin >> ch;
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            coin[i][j] = calc_coin(i, j);
        }
    }
    for (int i = 1; i <= n; ++ i) {
        if (tr[i][0] == ch) {
            now = (int)tr[i].size();
            st[i] ++ ;
            dfs(i);
            st[i] -- ;
        }
    }
    cout << ans;
}

P1101 单词方阵

#include <iostream>
using namespace std;
const int N = 110;

int n;
char g[N][N];
bool st[N][N];
string ss = "yizhong";

int dx[] = {-1, -1, -1, 0, 1, 1, 1, 0};
int dy[] = {-1, 0, 1, 1, 1, 0, -1, -1};

bool dfs(int x, int y, int u, int k) {
    if (u == 8) return true;
    if (g[x][y] != ss[u - 1]) return false;
    bool t = dfs(x + dx[k], y + dy[k], u + 1, k);
    st[x][y] |= t;
    return t;
}

int main() {
    cin >> n;
    for (int i = 0; i < n; ++ i) {
        cin >> g[i];
    }
    for (int i = 0; i < n; ++ i) {
        for (int j = 0; j < n; ++ j) {
            if (g[i][j] == 'y') {
                for (int k = 0; k < 8; ++ k) {
                    dfs(i, j, 1, k);
                }
            }
        }
    }
    for (int i = 0; i < n; ++ i) {
        for (int j = 0; j < n; ++ j) {
            if (st[i][j]) {
                cout << g[i][j];
            } else {
                cout << '*';
            }
        }
        cout << endl;
    }
}

P2404 自然数的拆分问题

#include <iostream>
#include <vector>
using namespace std;
const int N = 10;

int n;
int a[N];

void dfs(int u, int last, int sum) {
    if (sum > n) return ;
    if (sum == n) {
        for (int i = 1; i < u; ++ i) {
            cout << a[i];
            if (i != u - 1) cout << "+";
        }
        cout << endl;
        return ;
    }
    for (int i = last; i < n; ++ i) {
        a[u] = i;
        dfs(u + 1, i, sum + i);
    }
}

int main() {
    cin >> n;
    dfs(1, 1, 0);
}

P1596 [USACO10OCT]Lake Counting S

#include <iostream>
using namespace std;
const int N = 110;

int n, m;
char g[N][N];
bool st[N][N];

int dx[] = {-1, -1, -1, 0, 1, 1, 1, 0};
int dy[] = {-1, 0, 1, 1, 1, 0, -1, -1};

void dfs(int x, int y) {
    st[x][y] = true;
    for (int i = 0; i < 8; ++ i) {
        int nx = x + dx[i], ny = y + dy[i];
        if (nx < 0 || nx >= n || ny < 0 || ny >= m || st[nx][ny] || g[nx][ny] == '.') continue;
        dfs(nx, ny);
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; ++ i) {
        cin >> g[i];
    }
    int ans = 0;
    for (int i = 0; i < n; ++ i) {
        for (int j = 0; j < m; ++ j) {
            if (g[i][j] == 'W' && !st[i][j]) {
                ans ++ ;
                dfs(i, j);
            }
        }
    }
    cout << ans;
}

P1162 填涂颜色

第一想法是dfs后走不到的地方就是1或者2;但是注意那些被1围堵在角落的0,它们不是被1的闭合圈包围的,因此仍然是0,

一个好的想法便是在周围加一圈0,且从(0,0)开始搜索。这样的话,被堵在墙角的0可以通过旁边加上的0被dfs到

为什么必须从(0,0)开始搜索呢?因为如果(1,1)本身就是墙,且处于闭合圈的话,闭合圈内的0也会被dfs;而(0,0)是被加上的一圈0,不会出现这个问题

#include <iostream>
using namespace std;
const int N = 35;

int n;
int g[N][N];
bool st[N][N];

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};

void dfs(int x, int y) {
    st[x][y] = true;
    for (int i = 0; i < 4; ++ i) {
        int nx = x + dx[i], ny = y + dy[i];
//        if (nx < 1 || nx > n || ny < 1 || ny > n || st[nx][ny] || g[nx][ny] == 1) continue;
        if (nx < 0 || nx > n + 1 || ny < 0 || ny > n + 1 || st[nx][ny] || g[nx][ny] == 1) continue;
        dfs(nx, ny);
    }
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            cin >> g[i][j];
        }
    }
//    dfs(1, 1);
    dfs(0, 0);
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            if (g[i][j]) {
                cout << 1;
            } else if (st[i][j]) {
                cout << 0;
            } else {
                cout << 2;
            }
            cout << ' ';
        }
        cout << endl;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 算法7-4:深度优先搜索 1. 从起点开始,将其标记为已访问。 2. 对于起点的每个未访问的邻居,递归地执行步骤1-2。 3. 重复步骤2,直到没有未访问的邻居。 算法7-5:深度优先搜索(非递归) 1. 从起点开始,将其标记为已访问,并将其压入栈中。 2. 当栈不为空时,弹出栈顶元素,并对其每个未访问的邻居执行步骤1-2,并将其标记为已访问并压入栈中。 3. 重复步骤2,直到栈为空。 ### 回答2: 一、定义 深度优先搜索(Depth First Search,DFS)是图论中的基本算法,是从图的某个节点出发,访问这个节点,然后依次访问这个节点的每个未被访问的邻居节点,直至遍历完整个图。 二、实现 深度优先搜索可以通过递归或栈的方式实现。递归实现简单,但难以控制递归深度,容易发生栈溢出。栈的实现需要手动模拟栈,但可以灵活控制深度,避免栈溢出。 递归实现: 1.从某个节点v开始遍历。 2.标记该节点v为已访问。 3.对于v的每个未被访问的邻居节点w,递归访问w。 栈实现: 1.从某个节点v开始遍历。 2.将v入栈,并标记v为已访问。 3.当栈非空时循环执行以下步骤:弹出栈顶节点u,对于u的每个未被访问的邻居节点w,将w入栈并标记w为已访问。 三、应用 深度优先搜索可以用来判断图是否连通,可用于求解最小生成树、拓扑排序、连通分量等问题。 由于深度优先搜索需要存储所有已访问节点的路径,所以针对大规模图的遍历可能导致空间复杂度较高。 四、算法7-4,7-5代码分析 算法7-4: 算法7-4是对图的深度优先遍历的递归实现。首先遍历该节点,并标记为已访问,然后将该节点的所有邻居节点都遍历一遍。如果邻居节点未被访问,则对该节点进行递归调用进行遍历。 具体思路: 1.定义全局vis数组,用于记录节点是否已被访问。 2.定义一个函数dfs(u),对节点u进行深度优先遍历。遍历完u的所有邻居节点后,会回溯到该节点u的上一个节点。 3.主函数遍历所有节点,对未被访问的节点进行深度优先遍历。 算法7-5: 算法7-5是对图的深度优先遍历的栈实现。使用了一个栈来存储待访问节点。首先将初始节点加入栈中,并标记为已访问,然后循环遍历栈中的节点,直至栈为空。 具体思路: 1.定义全局vis数组,用于记录节点是否已被访问。 2.定义一个函数dfs(u),对节点u进行深度优先遍历。遍历完u的所有邻居节点后,会回溯到该节点u的上一个节点。 3.主函数遍历所有节点,对未被访问的节点进行深度优先遍历。在遍历到未被访问的节点时,加入栈中并标记为已访问,然后循环遍历栈中的节点,直至栈为空。 ### 回答3: 算法7-4,7-5是关于图的遍历中的深度优先搜索(DFS),主要是用来搜索和遍历图中所有的节点和边的算法。 深度优先搜索的核心思想是:从一个未访问的节点开始,深度优先遍历到最深处,然后回溯到上一个节点,再从上一个未遍历节点开始继续深度优先遍历。在具体实现过程中,我们可以使用递归或栈来实现深度优先搜索算法。 深度优先搜索算法在图的遍历、搜索、路径查找等方面有着广泛的应用,如迷宫问题、拓扑排序、关键路径等。 在算法7-4中,我们给出了使用递归实现深度优先搜索的伪代码: ```python void DFS(int u) { vis[u] = true; // 标记已经访问过 // 遍历所有邻接节点 for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; // 取出邻接节点 if (!vis[v]) { DFS(v); // 继续遍历 } } } ``` 而在算法7-5中,我们使用栈来实现深度优先搜索,具体实现过程如下: ```python void DFS(int u) { stack<int> s; // 定义一个栈 s.push(u); // 将起始节点放入栈中 vis[u] = true; // 标记已经访问过 while (!s.empty()) { int v = s.top(); // 取出栈顶节点 s.pop(); // 将该节点出栈 // 遍历所有邻接节点 for (int i = 0; i < G[v].size(); i++) { int w = G[v][i]; // 取出邻接节点 if (!vis[w]) { s.push(w); // 将未访问节点放入栈中 vis[w] = true; // 标记已访问 } } } } ``` 总之,深度优先搜索算法是一种基本的图遍历算法,其核心思想和实现方法都比较简单,但是能够灵活应用在众多图相关的算法问题中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值