zoukankan      html  css  js  c++  java
  • 搜索——基础篇

    1.入门级

    hdu 1010 Tempter of the Bone

    注意BFS是向4个方向同时扩展,搜索的一定是最短路径。如果把用掉的点标记:

    2 2 3
    S.
    D.

    这组数据用BFS只能搜到1,不能搜到3的路径。BFS不知道怎么剪枝才能不超时。

    DFS解法:

    /*------------------------------------------------
    @file      hdu1010
    解题:
    优化:
    
     
    @author    fripSide
    @date      2014/02/16
    ------------------------------------------------*/
    
    #include <cstdio>
    #include <cmath>
    #include <memory.h>
    
    using namespace std;
    
    char maze[9][9];
    
    int go[4][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}};
    
    int n, m, t;
    int sx, sy, ex, ey;
    
    bool DFS(int x, int y, int cnt) {
        if (cnt == t) {
            if (x == ex && y == ey) {
                return true;
            }
            return false;
        } else if (cnt > t) {
            return false;
        }
        if (abs(x - ex) + abs(y - ey) > t - cnt) {
            return false;
        }
        for (int i = 0; i < 4; ++i) {
            int cx = x + go[i][0];
            int cy = y + go[i][1];
            if (cx >= 0 && cx < n && cy >= 0 && cy < m && maze[cx][cy] != 'X') {
                maze[cx][cy] = 'X';
                if (DFS(cx, cy, cnt + 1)) {
                    return true;
                }
                maze[cx][cy] = '.';
            }
        }
        return false;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    
        while (scanf("%d%d%d", &n, &m, &t) != EOF && n != 0) {
            int r = 0;
            for (int i = 0; i < n; ++i) {
                scanf("%s", maze[i]);
                for (int j = 0; j < m; ++j) {
                    if (maze[i][j] == 'S') {
                        sx = i;
                        sy = j;
                    } else if (maze[i][j] == 'D') {
                        ex = i;
                        ey = j;
                    } else if (maze[i][j] == '.') {
                        r++;
                    }
                }
            }
            if (r + 1 < t || (sx + sy + ex + ey + t) % 2 == 1) {
                puts("NO");
                continue;
            }
            maze[sx][sy] = 'X';
            puts(DFS(sx, sy, 0) ? "YES" : "NO");
        }
        return 0;
    }
    View Code

    这个解法100+ms,优化:

    1.扩大maze,避免边界判断(可以优化到50ms以内)

    2.一开始就剪枝

     hdu-1241-Oil Deposits

    DFS解法:

    /*------------------------------------------------
    @file      hdu1241
    解题:
    
     
    @author    fripSide
    @date      2014/02/18
    ------------------------------------------------*/
    
    #include <cstdio>
    #include <memory.h>
    
    char maze[105][105];
    bool mark[105][105];
    
    int go[8][2] = {{1,0}, {-1,0}, {0,1}, {0,-1}, {1,1}, {1,-1}, {-1,1}, {-1,-1}};
    
    void DFS(int x, int y) {
        for (int i = 0; i < 8; ++i) {
            int cx = x + go[i][0];
            int cy = y + go[i][1];
            if (maze[cx][cy] == '@' && !mark[cx][cy]) {
                mark[cx][cy] = true;
                DFS(cx, cy);
            }
        }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
        int n, m;
        while (scanf("%d%d", &n, &m) != EOF && n != 0) {
            memset(maze, '*', sizeof maze); //避免判断边界
            memset(mark, false, sizeof mark);
            for (int i = 1; i <= n; ++i) {
                scanf("%s", maze[i] + 1);
            }
            int ans = 0;
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (maze[i][j] == '@' && !mark[i][j]) {
                        DFS(i, j);
                        ans++;
                    }
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

     hdu-1242-Rescue

    注意:BFS求出的路径是步数最少,而本题中经过X时间要+2,所以在选择路径时应该用优先权队列。

    优先权队列实现的两种方法:

    用小顶堆:

    struct N {
        int x, y;
        int t;
        bool operator > (const N & n) const {
            return t > n.t;
        }
    };
    priority_queue<N,vector<N>, greater<N> > Q;
    View Code

    或者:直接用大顶堆

    struct N {
        int x, y;
        int t;
        bool operator < (const N & n) const {
            return t > n.t;//让<返回逆序的结果
        }
    };
    priority_queue<N> Q;
    View Code
    /*------------------------------------------------
    @file      hdu1241t
    解题:
    
     
    @author    fripSide
    @date      2014/02/18
    ------------------------------------------------*/
    
    #include <cstdio>
    #include <memory.h>
    #include <queue>
    #include <functional>
    #include <vector>
    
    using namespace std;
    
    char maze[205][205];
    bool mark[205][205];
    int go[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    
    struct N {
        int x, y;
        int t;
        bool operator > (const N & n) const {
            return t > n.t;
        }
    };
    priority_queue<N, vector<N>, greater<N> > Q;
    
    int BFS() {
        while (!Q.empty()) {
            N cnt = Q.top();
            Q.pop();
            for (int i = 0; i < 4; ++i) {
                int cx = cnt.x + go[i][0];
                int cy = cnt.y + go[i][1];
                if (mark[cx][cy]) {
                    continue;
                }
                if (maze[cx][cy] == 'a') {
                    return cnt.t + 1;
                }
                if (maze[cx][cy] != '#') {
                    N tmp;
                    tmp.x = cx;
                    tmp.y = cy;
                    if (maze[cx][cy] == '.') {
                        tmp.t = cnt.t + 1;
                    } else {
                        tmp.t = cnt.t + 2;
                    }
                    Q.push(tmp);
                    mark[cx][cy] = true;
                }
            }
        }
        return -1;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
        int n, m;
        while (scanf("%d%d", &n, &m) != EOF) {
            memset(maze, '#', sizeof maze);
            for (int i = 1; i <= n; ++i) {
                scanf("%s", maze[i] + 1);
                maze[i][m + 1] = '#';
            }
            N tmp;
            int maxn = -1;
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    if (maze[i][j] == 'r') {
                        memset(mark, false, sizeof mark);
                        while (!Q.empty()) {
                            Q.pop();
                        }
                        mark[i][j] = true;
                        tmp.t = 0;
                        tmp.x = i;
                        tmp.y = j;
                        Q.push(tmp);
                        int ans = BFS();
                        if (ans != -1 && ans < maxn || maxn == -1) {
                            maxn = ans;
                        }
                    } 
                }
            }
            
            if (maxn == -1) {
                puts("Poor ANGEL has to stay in the prison all his life.");
            } else {
                printf("%d
    ", maxn);
            }
        }
        return 0;
    }
    View Code

     hdu 1026 Ignatius and the Princess I

    注意:

    1: 首先知道 广搜 + 优先队列。因为要求出时间最短,且从队列里先出来的不一定最优(仅当所有的点花的时间相同时是最优)。
    2: 路径的处理:由于搜索时,每一个节点可以推出多个节点(一对多关系):这些后继中只有一个是对的;
    而反过来,每个节点的前驱只有一个。 所以可以用前驱保存关系,待会再从末尾到开始反着找关系。或者倒着搜索。

    倒着搜索:

    /*------------------------------------------------
    @file      hdu1026
    解题:
    广度优先的时候,一个点的后继结点有好几种可能,但前驱结点只有一个。
     
    @author    fripSide
    @date      2014/02/18
    ------------------------------------------------*/
    
    #include <cstdio>
    #include <memory.h>
    #include <queue>
    
    using namespace std;
    
    char maze[105][105];
    int go[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    struct N {
        int x, y;
        int t;
        bool operator < (const N& n) const {
            return t > n.t;
        }
    };
    
    priority_queue<N> Q; //小顶堆
    
    struct P {
        int nx, ny;
        int fight;
    } path[105][105]; //记录路径
    
    int BFS() {
        while (!Q.empty()) {
            N cnt = Q.top();
            Q.pop();
            if (cnt.x == 1 && cnt.y == 1) {
                return cnt.t;
            }
            for (int i = 0; i < 4; ++i) {
                int cx = cnt.x + go[i][0];
                int cy = cnt.y + go[i][1];
                if (maze[cx][cy] != 'X') {
                    N tmp;
                    tmp.x = cx;
                    tmp.y = cy;
                    tmp.t = cnt.t + 1;
                    int fight = 0;
                    if (maze[cx][cy] != '.') {
                        fight = maze[cx][cy] - '0';
                    }
                    tmp.t += fight;
                    Q.push(tmp);
                    maze[cx][cy] = 'X';
                    path[cx][cy].nx = cnt.x;
                    path[cx][cy].ny = cnt.y;
                    path[cx][cy].fight = fight;
                }
            }
        }
        return -1;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
        int n, m;
        while (scanf("%d%d", &n, &m) != EOF) {
            memset(maze, 'X', sizeof maze);
            for (int i = 1; i <= n; ++i) {
                scanf("%s", maze[i] + 1);
                maze[i][m + 1] = 'X';
            }
            while (!Q.empty()) {
                Q.pop();
            }
            N tmp;
            tmp.x = n;
            tmp.y = m;
            tmp.t = 0;
            Q.push(tmp);
            if (maze[n][m] != '.') {
                path[n][m].fight = maze[n][m] - '0';
            }
            maze[n][m] = 'X';
            int ans = BFS();
            if (ans == -1) {
                puts("God please help our poor hero.");
            } else {
                ans += path[n][m].fight;
                printf("It takes %d seconds to reach the target position, let me show you the way.
    ", ans);
                int pos = 0;
                int x = 0;
                int y = 0;
                while (pos < ans) {
                    int cx = path[x + 1][y + 1].nx - 1;
                    int cy = path[x + 1][y + 1].ny - 1;
                    printf("%ds:(%d,%d)->(%d,%d)
    ", ++pos, x, y, cx, cy);
                    for (int i = 0; i < path[cx + 1][cy + 1].fight; ++i) {
                        printf("%ds:FIGHT AT (%d,%d)
    ", ++pos, cx, cy);
                    }
                    x = cx;
                    y = cy;
                }
            }
            puts("FINISH");
        }
        return 0;
    }
    View Code
    总想把每一篇文章精雕细琢之后以完美的面貌示人,就像演员在演出前都要彩排,总想准备好之后再去展现精彩的一面,但人生的每一刻都是精彩的,就算现在还不完善也要发出来,作为自己一直在学习的一种见证。
  • 相关阅读:
    HDU 6043
    HDU 6033
    HDU 6041
    HDU 6050
    HDU 6053
    HDU 6055
    HDU 6045
    HDU 6044
    HDU 6040
    ZUFE 1035 字符宽度编码(字符串)
  • 原文地址:https://www.cnblogs.com/fripside/p/3551666.html
Copyright © 2011-2022 走看看