SCAU算法设计与分析 —— 搜索算法

3 阅读5分钟

By 三石吖 2026.2

  • 本章节有点困难,只写了一部分,剩下有空再补吧

  • 搜索,太困难了!

5.搜索算法

8600 骑士问题

正常广搜即可,没啥坑点

  • 时间复杂度O(64T)O(64T)TT为测试组数
#include<bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;

constexpr int dx[] = {1, 2, 2, 1, -1, -2, -2, -1};
constexpr int dy[] = {-2, -1, 1, 2, -2, -1, 1, 2};
void solve(){
    int b;
    int num = 0;
    while(1){
        num++;
        std::cin >> b;
        if(b == -1){
            return;
        }

        std::vector<std::vector<int>>a(8, std::vector<int>(8));
        for(int i = 0; i < b; i++){
            char c;
            int r;
            std::cin >> c >> r;
            a[8 - r][c - 'a'] = 1;
        }

        int sr, sc, er, ec;
        char c1, c2;
        std::cin >> c1 >> sr >> c2 >> er;
        sr = 8 - sr, er = 8 - er;
        sc = c1 - 'a', ec = c2 - 'a';

        std::queue<pii>que;
        std::vector<std::vector<int>>vis(8, std::vector<int>(8));
        vis[sr][sc] = 1;
        que.push({sr, sc});
        int min = -1;
        int cnt = 0;
        while(!que.empty()){
            int siz = que.size();
            for(int k = 0; k < siz; k++){
                int x = que.front().first, y = que.front().second;
                que.pop();
                if(x == er && y == ec){
                    min = cnt;
                    break;
                }

                for(int i = 0; i < 8; i++){
                    int r = x + dx[i], c = y + dy[i];
                    if(r >= 0 && r < 8 && c >= 0 && c < 8 && !a[r][c] && !vis[r][c]){
                        vis[r][c] = 1;
                        que.push({r, c});
                    }
                }
            }
            if(min != -1){
                break;
            }
            cnt++;
        }

        if(min == -1){
            std::cout << "Board " << num << ":not reachable\n";
        }else{
            std::cout << "Board " << num << ":" << min << " moves\n";
        }
    }
}             

int main(){ 
    std::ios::sync_with_stdio(false);    
    std::cin.tie(nullptr);

#ifdef LOCAL
    freopen("make.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif

    int T = 1;
    // std::cin >> T;
    while(T--){
        solve();
    }
    return 0; 
}   
/* 

*/  

8603 子集和问题

这题直接爆搜就能过,感觉很没有道理

如果是输出任意一种方案的话,直接做0101背包然后找一下方案即可

搜索做法看看就行了

  • 时间复杂度O(2n)O(2^n)
#include<bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;

void solve(){
    int n, c;
    std::cin >> n >> c;
    std::vector<int>a(n);
    for(int i = 0; i < n; i++){
        std::cin >> a[i];
    }
    std::vector<int>ans, p;

    auto dfs = [&] (auto &&self, int sum, int inx) -> bool {
        if(sum == c){
            ans = p;
            return true;
        }
        if(inx >= n){
            return false;
        }
        p.push_back(a[inx]);
        if(self(self, sum + a[inx], inx + 1)){
            return true;
        }
        p.pop_back();
        if(self(self, sum, inx + 1)){
            return true;
        }
        return false;
    };

    if(dfs(dfs, 0, 0)){
        for(auto c : ans){
            std::cout << c << " ";
        }
        std::cout << "\n";
    }else{
        std::cout << "No Solution\n";
    }
}             

int main(){ 
    std::ios::sync_with_stdio(false);    
    std::cin.tie(nullptr);

#ifdef LOCAL
    freopen("make.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif

    int T = 1;
    // std::cin >> T;
    while(T--){
        solve();
    }
    return 0; 
}   
/* 

*/  

8604 运动员最佳配对问题

发现其实并不太能贪心,而数据范围极小,于是考虑搜索

在搜索时,我们实际只需要开一个数组男运动员或女运动员的编号,然后跑全排列即可,另外一组固定为0,1,2...n0,1,2...n这样,就能不重不漏地跑完了

  • 时间复杂度O(n!×n)O(n! \times n)
#include<bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;

void solve(){
    int n;
    std::cin >> n;
    std::vector<std::vector<int>>P(n, std::vector<int>(n));
    std::vector<std::vector<int>>Q(n, std::vector<int>(n));
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            std::cin >> P[i][j];
        }
    }
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            std::cin >> Q[i][j];
        }
    }

    std::vector<int>a(n);
    for(int i = 0; i < n; i++){
        a[i] = i;
    }
    int ans = 0;
    do{
        int tmp = 0;
        for(int i = 0; i < n; i++){
            tmp += P[a[i]][i] * Q[i][a[i]];
        }
        ans = std::max(ans, tmp);
    }while(std::next_permutation(a.begin(), a.end()));
    
    std::cout << ans << "\n";
}             

int main(){ 
    std::ios::sync_with_stdio(false);    
    std::cin.tie(nullptr);

#ifdef LOCAL
    freopen("make.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif

    int T = 1;
    // std::cin >> T;
    while(T--){
        solve();
    }
    return 0; 
}   
/* 

*/  

11089 多机最佳调度

(1)贪心:让耗时最多的工作给最早空闲的机器,维护一个小根堆即可,复杂度O(nlogn)O(nlogn)

(2)搜索:枚举每个工作给每台机器的情况,然后剪枝,维护当前能获得的最小答案,如果比这个答案还大的话不进入递归,但这样最劣还是会达到O(mn)O(m^n),不知道为啥能过,感觉没啥道理

#include<bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;

void solve(){
    int n, m;
    std::cin >> n >> m;
    std::vector<int>t(n);
    for(int i = 0; i < n; i++){
        std::cin >> t[i];
    }
    std::sort(t.begin(), t.end(), std::greater<>());
    std::priority_queue<int, std::vector<int>, std::greater<>>que;
    int ans1 = 0;
    for(int i = 0; i < m; i++){
        que.push(0);
    }

    for(int i = 0; i < n; i++){
        int x = que.top();
        que.pop();
        que.push(x + t[i]);
        ans1 = std::max(ans1, x + t[i]);
    }


    std::vector<int>cur(m);
    int ans2 = inf;
    auto dfs = [&](auto &&self, int inx) -> void {
        if(inx >= n){
            int tmp = *std::max_element(cur.begin(), cur.end());
            ans2 = std::min(ans2, tmp);
            return;
        }

        for(int i = 0; i < m; i++){
            if(cur[i] + t[inx] >= ans2){
                continue;
            }
            cur[i] += t[inx];
            self(self, inx + 1);
            cur[i] -= t[inx];
        }
    };

    dfs(dfs, 0);
    std::cout << ans1 << "\n" << ans2 << "\n";
}             

int main(){ 
    std::ios::sync_with_stdio(false);    
    std::cin.tie(nullptr);

#ifdef LOCAL
    freopen("make.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif

    int T = 1;
    // std::cin >> T;
    while(T--){
        solve();
    }
    return 0; 
}   
/* 

*/  

17085 工作分配问题

对人进行全排列然后统计答案

  • 时间复杂度O(n!×n)O(n! \times n)
#include<bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;

void solve(){
    int n;
    std::cin >> n;
    std::vector<std::vector<int>>C(n, std::vector<int>(n));
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            std::cin >> C[i][j];
        }
    }
    std::vector<int>a(n);
    for(int i = 0; i < n; i++){
        a[i] = i;
    }

    int ans = inf;
    std::vector<int>res;
    do{
        int sum = 0;
        for(int i = 0; i < n; i++){
            sum += C[i][a[i]];
        }

        if(sum < ans){
            ans = sum;
            res = a;
        }
    }while(std::next_permutation(a.begin(), a.end()));
    
    std::cout << ans << "\n";
    for(int i = 0; i < n; i++){
        std::cout << res[i] + 1 << " \n"[i == n - 1];
    }
}             

int main(){ 
    std::ios::sync_with_stdio(false);    
    std::cin.tie(nullptr);

#ifdef LOCAL
    freopen("make.txt", "r", stdin);
    freopen("a.txt", "w", stdout);
#endif

    int T = 1;
    // std::cin >> T;
    while(T--){
        solve();
    }
    return 0; 
}   
/* 

*/