算法基础模板整理(基础搜索篇)

Posted MAKISE004

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法基础模板整理(基础搜索篇)相关的知识,希望对你有一定的参考价值。

递归实现枚举

递归实现指数型枚举

void dfs(int k)
    if(k > n) 
        for(auto &x : res) cout << x << \' \';
        cout << endl;  return;
    
    
    dfs(k + 1);
    
    res.push_back(k);
    dfs(k + 1);
    res.pop_back();

递归实现排列型枚举

void dfs(int k)
    if(k > n)
        for(int i = 1; i <= n; i ++ ) cout << a[i] << \' \';
        cout << endl;  return;
    
    
    for(int i = 1; i <= n; i ++ )
        if(st[i]) continue;
        st[i] = true;
        a[k] = i;
        dfs(k + 1);
        st[i] = false;
    

递归实现组合型枚举

void dfs(int k)
    int nn = res.size();
    if(nn > m || m - nn > n - k + 1) return;
    if(k > n)
        for(auto &x : res) cout << x << \' \';
        cout << endl;
    
    
    res.push_back(k);
    dfs(k + 1);
    res.pop_back();
    
    dfs(k + 1);
              


BFS求最短路

void bfs()           // 经典二维数组中 bfs 求最短路
    queue<pii> q;
    q.push(0, 0);
    vis[0][0] = true;
    
    int res = 0;
    while(!q.empty())
        int nn = q.size();
        for(int i = 0; i < nn; i ++ )
            auto [x, y] = q.front();
            q.pop();
            if(x == n - 1 && y == m - 1) 
                cout << res;
                return;
            
            for(int k = 0; k < 4; k ++ )
                int nx = x + dx[k], ny = y + dy[k];
                if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if(vis[nx][ny] || g[nx][ny]) continue;
                q.push(nx, ny);
                vis[nx][ny] = true;
            
        
        res ++ ;  //也可开一个dist数组来记录最短路 且可以恰好省去vis数组
    


int bfs()               // 树 or 图 上求点的层次
    queue<int> q; q.push(1);
    memset(d, -1, sizeof(d));
    d[1] = 0;
    
    while(!q.empty())
        int u = q.front();
        q.pop();
        for(int i = h[u]; i != -1; i = ne[i])
            int v = e[i];
            if(d[v] != -1) continue;
            q.push(v), d[v] = d[u] + 1;
        
    
    return d[n];



DFS判断连通性

bool dfs(int x, int y)      //判断两点是否可达
    vis[x][y] = true;
    if(x == desx && y == desy) return true;
    for(int k = 0; k < 4; k ++ )
        int nx = x + dx[k], ny = y + dy[k];
        if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
        if(vis[nx][ny] || g[nx][ny] == \'#\') continue;
        if(dfs(nx, ny)) return true;
    
    return false;



//----------------------------------------

void dfs(int x, int y)    //求连通块个数    也可用bfs
    vis[x][y] = true;
    for(int k = 0; k < 8; k ++ )
        int nx = x + dx[k], ny = y + dy[k];
        if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
        if(vis[nx][ny] || g[nx][ny] == \'#\') continue;
        dfs(nx, ny);
    


for(int i = 0; i < n; i ++ )
    for(int j = 0; j < m; j ++ )
        if(g[i][j] == \'.\' && !vis[i][j])
            dfs(i, j), ans ++ ;


DFS求树的直径

int c;   //记录第一次dfs得到的端点
void dfs(int u, int fa)
    for(auto &[v, w] : e[u])
        if(v != fa)
            dist[v] = dist[u] + w;
            if(dist[v] > dist[c]) c = v;  //记录最远的点
            dfs(v, u);
        


int main()
    cin >> n;
    for(int i = 1; i < n; i ++ )
        int u, v, w; cin >> u >> v >> w;
        e[u].push_back(make_pair(v, w));
        e[v].push_back(make_pair(u, w));
    
    
    dfs(1, 0);     //找到一个端点c
    dist[c] = 0;
    dfs(c, 0);     //找到c对应的端点
    
    cout << dist[c];

DFS求树的重心

int dfs(int u)
    vis[u] = true;
    int sum = 1, res = 0;  
    for(int i = h[u]; i != -1; i = ne[i])
        int v = e[i];
        if(!vis[v])
            int s = dfs(v);
            res = max(res, s);
            sum += s;
        
    
    res = max(res, n - sum);//以u为起点向下的最大连通块 向上的连通块 较大者
    ans = min(res, ans);
    return sum;



回溯

DFS搜索经典案例(Acwing 1116.马走日)

void dfs(int x, int y, int cnt)
    if(cnt == n * m)   //走满图中所有的点
        res ++ ;
        return;
    
    
    for(int k = 0; k < 8; k ++ )
        int nx = x + dx[k], ny = y + dy[k];
        if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
        if(vis[nx][ny]) continue;
        
        vis[nx][ny] = true;
        dfs(nx, ny, cnt + 1);
        vis[nx][ny] = false;
    

DFS剪枝经典案例(Acwing 165.小猫爬山)

void dfs(int k, int cnt)
    if(cnt >= res) return;   //剪枝
    if(k > n)
        res = min(res, cnt);
        return;
    
    //枚举已有的车是否可存
    for(int i = 1; i <= cnt; i ++ )
        if(t[i] + a[k] <= W)
            t[i] += a[k];
            dfs(k + 1, cnt);  
            t[i] -= a[k];
        
    

    t[cnt + 1] += a[k];
    dfs(k + 1, cnt + 1);   //新开一辆车
    t[cnt + 1] -= a[k];




状态压缩 递推

经典示例(Acwing 95.费解的开关)

void turn(int x, int y)
    for(int k = 0; k < 5; k ++ )
        int nx = x + dx[k], ny = y + dy[k];
        if(nx < 0 || nx >= 5 || ny < 0 || ny >= 5) continue;
        g[nx][ny] ^= 1;
    


int main()
    int t; cin >> t;
    while(t -- )
        for(int i = 0; i < 5; i ++ ) cin >> g[i];
        int ans = 1e7;
        for(int k = 0; k < 1 << 5; k ++ )
            int step = 0;
            memcpy(backup, g, sizeof(g));
            //枚举第一行如何操作
            for(int i = 0; i < 5; i ++ )
                if(k >> i & 1)
                    step ++ ;
                    turn(0, i);
                
            //从第一行开始到第四行,依次改变下一行的对应位置的开关
            for(int i = 0; i < 4; i ++ )
                for(int j = 0; j < 5; j ++ )
                    if(g[i][j] == \'0\')
                        step ++ ;
                        turn(i + 1, j);
                    
            //验证最后一行是否都是亮的
            bool dark = false;
            for(int i = 0; i < 5; i ++ )
                if(g[4][i] == \'0\')
                    dark = true;
                    break;
                
            if(!dark) ans = min(ans, step);
            memcpy(g, backup, sizeof(backup));
        
        if(ans <= 6) cout << ans << endl;
        else cout << -1 << endl;
    

深度优先搜索算法基础模板

 1 void DFS(检索状态)
 2 {
 3     if(到达目标状态)
 4     {
 5         ...// 根据题意添加
 6         return; 
 7     }
 8     
 9     if(越界或是不合法状态) return;
10      
11     for(扩展方式)
12     {
13         if(扩展方式所达到状态合法)
14         {
15             ....//根据题意来添加
16             标记; 
17             DFS(); // 递归调用 
18             修改(剪枝); 
19             还原标记; 
20             //是否还原标记根据题意
21             //如果加上(还原标记)就是 回溯法
22         }
23     }
24     return; 
25 } 

 

以上是关于算法基础模板整理(基础搜索篇)的主要内容,如果未能解决你的问题,请参考以下文章

算法基础1舍友课间上了个厕所,回来就告诉我他掌握了二分查找内附搜索模板

0基础学算法 搜索篇第一讲 深度优先搜索

深度优先搜索算法基础模板

Django基础篇--模板和路由分发

算法篇:地图算法取经之路

算法篇:地图算法取经之路