poj-2049 dfs

来源:互联网 发布:类似淘宝的app 编辑:程序博客网 时间:2024/05/05 07:47
//7148K 94MS G++
#include <stdio.h>
#include <string.h>

struct WallCell {
    char upWall;    // 0, no wall. 1, has door. 2, has wall
    char rightWall;

};

typedef struct WallCell WallCell;

// seaMap[i][j] indicates the wall info from (i, j) to (i+1, j)<upWall> and (i, j) to (i, j+1)<rightWall>
WallCell seaMap[1000][1000];
int seaMapFlag[1000][1000];

#define INF 100000

//return -1 if can not go on, else the door num
char dfs(int x, int y, int minX, int minY, int maxX, int maxY) {
    // printf("dfs %d %d\n", x, y);

    char leftWall = seaMap[x][y].upWall;
    char downWall = seaMap[x][y].rightWall;
    char rightWall = seaMap[x+1][y].upWall;
    char upWall =  seaMap[x][y+1].rightWall;

    if (leftWall < 2 && (seaMapFlag[x-1][y] > seaMapFlag[x][y] + leftWall)) { // try to enter left cell x->x-1
        
        seaMapFlag[x-1][y] = seaMapFlag[x][y] + leftWall;
        dfs(x-1, y, minX, minY, maxX, maxY);
    }
    if (downWall < 2 && (seaMapFlag[x][y-1] > seaMapFlag[x][y] + downWall)) {  // try to enter down cell  y->y-1
        seaMapFlag[x][y-1] =  seaMapFlag[x][y] + downWall;
        dfs(x, y-1, minX, minY, maxX, maxY);
    }
    if (rightWall < 2 && (seaMapFlag[x+1][y] > seaMapFlag[x][y] + rightWall)) { // try to enter right cell x->x+1
        seaMapFlag[x+1][y] = seaMapFlag[x][y] + rightWall;
        dfs(x+1, y, minX, minY, maxX, maxY);
    }
    if (upWall < 2 && (seaMapFlag[x][y+1] > seaMapFlag[x][y] + upWall)) { // try to enter up cell y->y+1
        seaMapFlag[x][y+1] = seaMapFlag[x][y] + upWall;
        dfs(x, y+1, minX, minY, maxX, maxY);
    }

    return -1;
}

void hardEnEdge(int maxX, int maxY) {
    // printf("hardEnEdge %d %d\n", maxX, maxY);
    for (int i = 0; i <= maxX-1; i++) {
        seaMap[i][0].rightWall = 2;
        seaMap[i][maxY].rightWall = 2;
    }
    // printf("hardEnEdge 1\n");
    for (int i = 0; i <= maxY-1; i++) {
        seaMap[0][i].upWall = 2;
        seaMap[maxX][i].upWall = 2;
    }
    // printf("hardEnEdge 2\n");
}

void getMinDoor(float beginX, float beginY, int minX, int minY, int maxX, int maxY) {
    // printf("%f %f %d %d %d %d\n", beginX, beginY, minX, minY, maxX, maxY);
    for (int i = 0; i <= maxX; i++) {
        for (int j = 0; j <= maxY; j++) {
            seaMapFlag[i][j] = INF;
        }
    }
    seaMapFlag[(int)beginX][(int)beginY] = 0;
    dfs((int)beginX, (int)beginY, minX, minY, maxX, maxY);
    printf("%d\n", seaMapFlag[0][0] == INF ? -1 : seaMapFlag[0][0]);
}

int main() {
    int M;
    int N;
    while(1) {
        int minX = 9999, minY = 9999, maxX = -9999, maxY = -9999;
        memset(seaMap, 0, sizeof(seaMap));
        memset(seaMapFlag, 0, sizeof(seaMapFlag));
        scanf("%d %d", &M, &N);
        if (-1 == M && -1 == N) {
            return 0;
        }
        for (int i = 0; i < M ; i++) {
            int x, y, direction, length;
            scanf("%d %d %d %d", &x, &y, &direction, &length);
            minX = x < minX ? x : minX;
            minY = y < minY ? y : minY;
            if (!direction) { //paralell to X-axis
                maxX = x + length > maxX ? x + length : maxX;
                maxY = y + 0 > maxY ? y + 0 : maxY;
            } else { //paralell to Y-axis
                maxY = y + length > maxY ? y + length : maxY;
                maxX = x + 0 > maxX ? x + 0 : maxX;
            }
            for (int i = 0; i < length; i++) {
                direction == 0 ? seaMap[x+i][y].rightWall = 2 : seaMap[x][y+i].upWall = 2;
            }
        }
        for (int j = 0; j < N; j++) {
            int x, y, direction;
            scanf("%d %d %d", &x, &y, &direction);
            direction == 0 ? seaMap[x][y].rightWall = 1 : seaMap[x][y].upWall = 1;
            if (!direction) { //paralell to X-axis
                maxX = x + 1 > maxX ? x + 1 : maxX;
                maxY = y + 0 > maxY ? y + 0 : maxY;
            } else { //paralell to Y-axis
                maxY = y + 1 > maxY ? y + 1 : maxY;
                maxX = x + 0 > maxX ? x + 0 : maxX;
            }
        }
        float sbX, sbY;
        scanf("%f %f", &sbX, &sbY);

        if (!M & !N) {
            printf("0\n");
            continue;
        }

        if (sbX < 0 || sbY < 0 || sbX > 199 || sbY > 199) {
            printf("0\n");
            continue;
        }
        maxX = maxX > (int)sbX ? maxX : (int)sbX;
        maxY = maxY > (int)sbY ? maxY : (int)sbY;
        hardEnEdge(maxX + 1, maxY + 1);
        getMinDoor(sbX, sbY, minX, minY, maxX, maxY);
    }

}

2049的dfs版本,思想上其实没有变化,都是flood-fill的不断刷新每个格子到起始点的最少doorNum,只是遍历的手段从bfs换成了dfs。

这道题之所以和普通的迷宫题不一样,在于,一般迷宫要求的都是最少的移动次数,及从起始的格子节点到目的格子节点所需要的最短路径就是所求。

因此BFS就可以满足此需求,但是本题的特殊之处在于,要求的不是最少移动次数,而是通过的最少的门(有可能长的路径经过门少,短路径经过门多),

因此普通的BFS在这种情况下就不再适用了。

有点像带权重的图求解。

首先需要开一个二维数组A记录每个格子到起始格子所经过的最少door num, 注意的是这个door num都是不断在刷新的, 每次有新的路径要抵达这个点的时候,

要看从此路径到此点的doorNum是否比此格子当前存储的doornum还要小,如果小,那么更新此点,并且要重新遍历该点。

和普通的二维标记数组不一样,A在这里也是标示,但是是否需要遍历的标准从 是否遍历过 变成了新路径到该点的doornum是否更小(如果更小,那么以就要重新遍历)。

不清楚这个技法算是BFS/DFS的一部分,还是一种新的思想.

感觉好乱,无数的命运交叉口互相交织影响,最后写出大结局。

0 0