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\n", 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\n", 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.\n", 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)\n", ++pos, x, y, cx, cy);
                for (int i = 0; i < path[cx + 1][cy + 1].fight; ++i) {
                    printf("%ds:FIGHT AT (%d,%d)\n", ++pos, cx, cy);
                }
                x = cx;
                y = cy;
            }
        }
        puts("FINISH");
    }
    return 0;
}
View Code