8.14_15信息学集训_树、搜索与剪枝

二叉树

P1305 新二叉树

点击查看代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 310, INF = 0x3f3f3f3f;
char a, b, c, rt, tr[N][2];
int n;
// pre(u) : 先序遍历以 u 为根的子树
void pre(char u) {
    if (u == '*')
        return;
    cout << u;      // 遍历 u,即根节点
    pre(tr[u][0]);  // 遍历 u 的左儿子
    pre(tr[u][1]);  // 遍历 u 的右儿子
}
int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a >> b >> c;
        if (i == 0)
            rt = a;
        tr[a][0] = b;
        tr[a][1] = c;
    }
    pre(rt);
    return 0;
}

B3642 二叉树的遍历

点击查看代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6, INF = 0x3f3f3f3f;
int n, tr[N][2];
// struct Node {
//     int l, r;
// } tree[N]; // 还可以使用结构体封装左右儿子

// pre(u) : 先序遍历以 u 为根的子树
void pre(int u) {
    if (u == 0)
        return;
    cout << u << " ";  // 遍历 u,即根节点
    pre(tr[u][0]);     // 遍历 u 的左儿子
    pre(tr[u][1]);     // 遍历 u 的右儿子
}
void in(int u) {
    if (u == 0)
        return;
    in(tr[u][0]);      // 遍历 u 的左儿子
    cout << u << " ";  // 遍历 u,即根节点
    in(tr[u][1]);      // 遍历 u 的右儿子
}
void post(int u) {
    if (u == 0)
        return;
    post(tr[u][0]);    // 遍历 u 的左儿子
    post(tr[u][1]);    // 遍历 u 的右儿子
    cout << u << " ";  // 遍历 u,即根节点
}

int main() {
    cin >> n;
    for (int i = 1, l, r; i <= n; i++) {
        cin >> l >> r;
        tr[i][0] = l, tr[i][1] = r;
    }
    pre(1), cout << endl;
    in(1), cout << endl;
    post(1), cout << endl;
    return 0;
}

P4913 【深基16.例3】二叉树深度

点击查看代码
#include <bits/stdc++.h>  // 万能头
using namespace std;
const int N = 1e6 + 10;
struct T {
    int l, r;
} tree[N];

int dfs(int rt) {
    if (tree[rt].l == 0 && tree[rt].r == 0) return 1;
    return max(dfs(tree[rt].l), dfs(tree[rt].r)) + 1;
}
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1, l, r; i <= n; i++) {
        scanf("%d%d", &l, &r);
        tree[i].l = l;
        tree[i].r = r;
    }
    printf("%d\n", dfs(1));
    return 0;
}

P3884 [JLOI2009] 二叉树问题

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6, INF = 0x3f3f3f3f;
vector<int> g[N];
int n, v1, v2, v3, dep[N], st[N], p[N];

void dfs(int u, int d) {
    dep[u] = d, v1 = max(v1, d), v2 = max(v2, ++st[d]);
    for (auto v : g[u]) {
        p[v] = u, dfs(v, d + 1);
    }
}
int main() {
    cin >> n;
    int u, v;
    for (int i = 1; i <= n; i++) {
        cin >> u >> v;
        if (i < n) g[u].push_back(v);
    }
    dfs(1, 1);
    // u -> v
    int up = 0, down = 0;
    while (dep[u] > dep[v]) u = p[u], up++;
    while (dep[u] < dep[v]) v = p[v], down++;
    while (u != v) u = p[u], v = p[v], up++, down++;
    v3 = 2 * up + down;
    cout << v1 << endl << v2 << endl << v3 << endl;
    return 0;
}

P8681 [蓝桥杯 2019 省 AB] 完全二叉树的权值

点击查看代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int tr[N], w[N], k, n;
// w[d] :表示深度 d 的所有节点权值和
// dfs(u,d) : 遍历 u为 根节点的子树,深度为 d
void dfs(int u, int d) {
    if (u > n) return;
    w[d] += tr[u], k = max(k, d);
    dfs(2 * u, d + 1);
    dfs(2 * u + 1, d + 1);
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &tr[i]);  // 建树
    dfs(1, 1);

    int id = 1; // 节点权值和最大的深度
    for (int i = 1; i <= k; i++)
        if (w[id] < w[i]) id = i;
    printf("%d", id);
    return 0;
}

搜索

P1451 求细胞数量

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 110, INF = 0x3f3f3f3f;
int n, m, ans;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
string s[N];
bool st[N][N];

void dfs(int x, int y) {
    st[x][y] = 1;
    for (int i = 0; i < 4; i++) {
        int a = x + dx[i];
        int b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= m) continue;
        if (!st[a][b] && s[a][b] != '0') dfs(a, b);
    }
}
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        cin >> s[i];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            if (s[i][j] != '0' && !st[i][j])
                ans++, dfs(i, j);
    cout << ans;
    return 0;
}

P1596 [USACO10OCT] Lake Counting S

点击查看代码

P1605 迷宫

点击查看代码

P1706 全排列问题

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 22, INF = 0x3f3f3f3f;
int n;

namespace AC {
void solve() {
    int a[N];
    for (int i = 1; i <= n; i++)
        a[i] = i;
    do {
        for (int i = 1; i <= n; i++)
            cout << setw(5) << a[i];
        cout << endl;
    } while (next_permutation(a + 1, a + 1 + n));
}
};  // namespace AC

int a[N];    // a[i] 表示编号 i的凳子是谁在坐
bool st[N];  // st[i] 表示编号 i 是否坐下

// dfs(u) : 表示当前的第 u 个位置
void dfs(int u) {
    if (u > n) {
        for (int i = 1; i <= n; i++) cout << setw(5) << a[i];
        cout << endl; return;
    }
    for (int i = 1; i <= n; i++)
        if (!st[i]) { // 当前编号 i 的人还没有坐下
            st[i] = 1, a[u] = i, dfs(u + 1);  // 编号 i 坐在的第 u个凳子上
            st[i] = 0;
        }
}
int main() {
    cin >> n, dfs(1);
    // AC::solve();
    return 0;
}

// " \n"[i==n];
// int c = flag ? a : b;

P1157 组合的输出

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 22, INF = 0x3f3f3f3f;
int n, r;
int a[N];    // a[i] 表示编号 i的凳子是谁在坐
bool st[N];  // st[i] 表示编号 i 是否坐下

// dfs(u) : 表示当前的第 u 个位置
void dfs(int u) {
    if (u > r) {
        for (int i = 1; i <= r; i++)
            cout << setw(3) << a[i];
        cout << endl;
        return;
    }
    for (int i = 1; i <= n; i++)
        if (!st[i] && (u == 1 || a[u - 1] < i)) {  // i 可以坐下
            st[i] = 1, a[u] = i, dfs(u + 1);  // 编号 i 坐在的第 u个凳子上
            st[i] = 0;
        }
}
int main() {
    cin >> n >> r, dfs(1);
    return 0;
}

P1036 [NOIP2002 普及组] 选数

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 22, INF = 0x3f3f3f3f;
int n, r, num[N], ans;
int a[N];    // a[i] 表示编号 i的凳子是谁在坐
bool st[N];  // st[i] 表示编号 i 是否坐下

bool isp(int n) {
    for (int i = 2; i <= n / i; i++)
        if (n % i == 0)
            return 0;
    return n > 1;
}
// dfs(u) : 表示当前的第 u 个位置
void dfs(int u) {
    if (u > r) {
        int sum = 0;
        for (int i = 1; i <= r; i++) sum += num[a[i]];
        if (isp(sum)) ans++;
        return;
    }
    for (int i = 1; i <= n; i++)
        if (!st[i] && (u == 1 || a[u - 1] < i)) {  // 当前编号 i 的人还没有坐下
            st[i] = 1, a[u] = i, dfs(u + 1);  // 编号 i 坐在的第 u个凳子上
            st[i] = 0;
        }
}
int main() {
    cin >> n >> r;
    for (int i = 1; i <= n; i++) cin >> num[i];
    dfs(1), cout << ans;
    return 0;
}

P1443 马的遍历

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 410, INF = 0x3f3f3f3f;
int n, m, x, y, st[N][N];
int d[][2] = {-2, -1, -2, 1, -1, -2, -1, 2, 1, -2, 1, 2, 2, -1, 2, 1};

void bfs() {
    queue<pair<int, int> > q;
    q.push(make_pair(x, y)), st[x][y] = 1;
    while (q.size()) {
        auto it = q.front(); q.pop();
        x = it.first, y = it.second;
        for (int i = 0; i < 8; i++) {
            int a = x + d[i][0];
            int b = y + d[i][1];
            if (a < 1 || a > n || b < 1 || b > m || st[a][b]) continue;
            q.push({a, b}), st[a][b] = st[x][y] + 1;
        }
    }
}
int main() {
    cin >> n >> m >> x >> y, bfs();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cout << st[i][j] - 1 << " \n"[j == m];
    return 0;
}

P1135 奇怪的电梯

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 210, INF = 0x3f3f3f3f;
int n, a, b, k[N], st[N];

int bfs() {
    queue<int> q;
    q.push(a), st[a] = 1;
    while (q.size()) {
        auto u = q.front(); q.pop();
        if (u == b) return st[u] - 1;
        for (int i = 0; i < 2; i++) {
            int v = u + k[u] * (i % 2 ? 1 : -1);
            if (v > 0 && v <= n && !st[v])
                q.push(v), st[v] = st[u] + 1;
        }
    }
    return -1;
}
int main() {
    cin >> n >> a >> b;
    for (int i = 1; i <= n; i++) cin >> k[i];
    cout << bfs();
    return 0;
}

P1141 01迷宫

点击查看代码

P1219 [USACO1.5] 八皇后 Checker Challenge

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 27, INF = 0x3f3f3f3f;
int n, cnt;
int a[N];  // a[x]=y 第x行的皇后在 第 y 列
int b[N];  // b[y] 第 y 列是否存在皇后
int c[N];  // c[x+y]
int d[N];  // d[x-y+n]

// dfs(x) 当前在第 x 行放置棋子
void dfs(int x) {
    if (x > n) {
        ++cnt;
        if (cnt <= 3)
            for (int i = 1; i <= n; i++)
                cout << a[i] << " \n"[i == n];
        return;
    }
    for (int y = 1; y <= n; y++) {
        if (!b[y] && !c[x + y] && !d[x - y + n]) {  // 点(x,y)是否可以放
            a[x] = y, b[y] = c[x + y] = d[x - y + n] = 1;
            dfs(x + 1);
            b[y] = c[x + y] = d[x - y + n] = 0;
        }
    }
}
int main() {
    cin >> n, dfs(1), cout << cnt;
    return 0;
}

P1379 八数码难题

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 210, INF = 0x3f3f3f3f;
string a, target = "123804765";
int d[][2] = {-1, 0, 1, 0, 0, -1, 0, 1};

int bfs() {
    map<string, int> st;
    queue<string> q;
    q.push(a), st[a] = 1;
    while (q.size()) {
        auto u = q.front(); q.pop();
        if (u == target) return st[u] - 1;// 目标状态
        int p = u.find('0'), x = p / 3, y = p % 3;// 0 在(x,y)处
        for (int i = 0; i < 4; i++) {
            int a = x + d[i][0], b = y + d[i][1];
            if (a < 0 || a >= 3 || b < 0 || b >= 3) continue;
            string v(u); swap(v[p], v[a * 3 + b]);// 交换
            if (!st[v]) q.push(v), st[v] = st[u] + 1;
        }
    }
    return -1;
}
int main() {
    cin >> a, cout << bfs();
    return 0;
}

搜索剪枝

P1025 [NOIP2001 提高组] 数的划分

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int n, k, ans;

void dfs(int u, int cnt, int s) {
    // 可行性剪枝
    if (cnt >= k || s >= n) {
        if (cnt == k && s == n) ans++;
        return;
    }
    // 优化搜索顺序
    for (int i = u; i >= 1 && s + i * (k - cnt) >= n; i--) {
        dfs(i, cnt + 1, s + i);
    }
}
int main() {
    cin >> n >> k, dfs(n, 0, 0), cout << ans;
    return 0;
}

P5194 [USACO05DEC] Scales S

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
ll n, c, ans, sum[N];
int a[N];
// 1.dfs(u,s) 当前计划选择砝码 u,已选择和为 s。
// 2.出口: u==0
// 3.递归关系:u-1
void dfs(int u, ll s) {
    if (s > c) return;  // 可行性剪枝
    if (s + sum[u] <= ans) return;  // 最优性剪枝
    ans = max(ans, s);
    if (u == 0) return;
    dfs(u - 1, s + a[u]);
    dfs(u - 1, s);
}
int main() {
    cin >> n >> c;
    for (int i = 1; i <= n; i++)
        cin >> a[i], sum[i] = sum[i - 1] + a[i];
    dfs(n, 0), cout << ans;
    return 0;
}

P1434 [SHOI2002] 滑雪

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m, g[N][N], d[][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
int dp[N][N];

int dfs(int x, int y) {
    if (dp[x][y]) return dp[x][y];
    dp[x][y] = 1;
    for (int i = 0; i < 4; i++) {
        int a = x + d[i][0], b = y + d[i][1];
        if (a < 1 || a > n || b < 1 || b > m || g[a][b] >= g[x][y]) continue;
        dp[x][y] = max(dp[x][y], dfs(a, b) + 1);
    }
    return dp[x][y];
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) cin >> g[i][j];
    int ans = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) ans = max(ans, dfs(i, j));
    cout << ans;
}

P2383 狗哥玩木棒

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,m, w[30], k = 0;
bool flag;
void dfs(int step, int l1, int l2, int l3, int l4) {
    if (flag || l1 > k || l2 > k || l3 > k || l4 > k) return;
    if (step > m) {
        if (l1 == l2 && l1 == l3 && l1 == l4) flag = true;
        return;
    }
    dfs(step + 1, l1 + w[step], l2, l3, l4);
    dfs(step + 1, l1, l2 + w[step], l3, l4);
    dfs(step + 1, l1, l2, l3 + w[step], l4);
    dfs(step + 1, l1, l2, l3, l4 + w[step]);
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> m, k = 0;
        for (int j = 1; j <= m; j++) cin >> w[j], k += w[j];
        sort(w + 1, w + 1 + m, [](int x, int y) { return x > y; });
        k /= 4;
        flag = false, dfs(1, 0, 0, 0, 0);
        cout << (flag ? "yes" : "no") << endl;
    }
    return 0;
}

P1120 小木棍

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 110, INF = 0x3f3f3f3f;
int n, a[N], len, cnt;
bool st[N];

// dfs(now,length,last)
// 当前正在拼第now根原始木棒,且已经拼出长度length,上次使用的木棒last
bool dfs(int now, int length, int last) {
    if (now > cnt) return true;
    if (length == len) return dfs(now + 1, 0, 1);
    int fail = 0;
    for (int i = last; i <= n; i++) {
        if (!st[i] && length + a[i] <= len && fail != a[i]) {
            st[i] = 1;
            if (dfs(now, length + a[i], i + 1)) return true;
            st[i] = 0, fail = a[i];
            if (length == 0 || length + a[i] == len) return false;
        }
    }
    return false;
}
int main() {
    int sum = 0, val = 0; cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i], sum += a[i];
    sort(a + 1, a + 1 + n, greater<int>());
    for (len = a[n]; len <= sum; len++) {
        if (sum % len) continue;
        cnt = sum / len;
        memset(st, 0, sizeof st);
        if (dfs(1, 0, 1)) break;
    }
    cout << len << endl;
    return 0;
}

P1092 [NOIP2004 提高组] 虫食算

点击查看代码

P1032 [NOIP2002 提高组] 字串变换

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
string A, B, a, b;
map<pair<string, string>, bool> mp;
map<string, int> st;

void bfs() {
    queue<string> q;
    q.push(A), st[A] = 1;
    while (q.size()) {
        auto u = q.front(); q.pop();
        if (st[u] > 10) continue;
        if (u == B) {
            cout << st[u] - 1 << endl; return;
        }
        for (auto it : mp) {
            a = it.first.first, b = it.first.second;
            int p = u.find(a);
            while (p != -1) {
                string v = u;
                v.replace(v.begin() + p, v.begin() + p + a.size(), b);
                if (!st[v]) st[v] = st[u] + 1, q.push(v);
                p = u.find(a, p + a.size());
            }
        }
    }
    cout << "NO ANSWER!" << endl;
}
int main() {
    cin >> A >> B;
    while (cin >> a >> b) mp.insert({make_pair(a, b), 1});
    bfs();
    return 0;
}

P1019 [NOIP2000 提高组] 单词接龙

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int n, m, ans;
string s[N];
char start;
int g[N][N], use[N];

void dfs(int u, string str) {
    ans = max(ans, (int)str.size());
    use[u]++;
    for (int i = 0; i < n; i++)
        if (g[u][i] && use[i] < 2)
            dfs(i, str + s[i].substr(g[u][i]));
    use[u]--;
}
int main() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> s[i];
    cin >> start;

    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++) {
            int a = s[i].size(), b = s[j].size();
            for (int k = 1; k < min(a, b); k++)
                if (s[i].substr(a - k) == s[j].substr(0, k)) {
                    g[i][j] = k; break;
                }
        }
    for (int i = 0; i < n; i++)
        if (s[i][0] == start) dfs(i, s[i]);
    cout << ans;
}

P3958 [NOIP2017 提高组] 奶酪

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10, INF = 0x3f3f3f3f;
ll T, n, m, h, r, d, x[N], y[N], z[N];
bool st[N], flag = 0;

double dist(int p1, int p2) {
    return (double)sqrt(pow(x[p1] - x[p2], 2) + pow(y[p1] - y[p2], 2) +
                        pow(z[p1] - z[p2], 2));
}
namespace AC1 {
// 当前在第 u个空洞
void dfs(int u) {
    if (flag || abs(z[u] - h) <= r) {
        flag = 1;
        return;
    }
    st[u] = 1;
    for (int i = 1; i <= n; i++)
        if (!st[i] && dist(u, i) <= d)
            dfs(i);
}
void solve() {
    flag = 0, memset(st, 0x00, sizeof st);
    for (int i = 1; i <= n && !flag; i++)
        if (abs(z[i]) <= r)
            dfs(i);
}
};  // namespace AC1

namespace AC2 {
struct Node {
    ll x, y;
} g[N * N];
int p[N];
int find(int u) {
    return u == p[u] ? u : p[u] = find(p[u]);
}
bool solve() {
    m = 0;
    for (int i = 1; i <= n; i++)
        for (int j = i + 1; j <= n; j++)
            if (dist(i, j) <= d)
                g[++m] = {i, j};
    for (int i = 0; i <= n; i++)
        p[i] = i;
    for (int i = 1; i <= m; i++) {
        int a = find(g[i].x), b = find(g[i].y);
        if (a != b)
            p[a] = b;
    }
    flag = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (abs(z[i] - h) <= r && abs(z[j]) <= r && find(i) == find(j))
                return flag = 1;
    return 0;
}
};  // namespace AC2
int main() {
    cin >> T;
    while (T--) {
        cin >> n >> h >> r, d = 2 * r;
        for (int i = 1; i <= n; i++)
            cin >> x[i] >> y[i] >> z[i];
        // AC1::solve();
        AC2::solve();
        cout << (flag ? "Yes" : "No") << endl;
    }
    return 0;
}

P1040 [NOIP2003 提高组] 加分二叉树

点击查看代码

P1074 [NOIP2009 提高组] 靶形数独

点击查看代码

P2827 [NOIP2016 提高组] 蚯蚓

点击查看代码

T266208 小猫爬山

点击查看代码

posted @ 2024-08-14 12:06  HelloHeBin  阅读(43)  评论(0编辑  收藏  举报