poj-2056

来源:互联网 发布:印度 保法止 淘宝 编辑:程序博客网 时间:2024/06/06 07:35
// 736K    0MS G++
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

#define MAX 300
#define SEP 'S'
#define INF -99999

// int LineSInfo[MAX][2]; // MAX line, every line: [0] store S begin pos [1] store S end pos in this line

char LineSInfo[MAX][MAX];

char pointFlag[MAX][MAX]; // 0 white, 1 grey, 2 black

struct LineSExpandOption {
    char expand;
    char noExpand;
};

typedef struct LineSExpandOption LineSExpandOption;

LineSExpandOption lineSExpandOption[MAX];

int M;
int N;


struct Point {
    int x;
    int y;
    char used;
    int step;
};

typedef struct Point Point;

Point beginPoints[2];
Point endPoints[2];

queue<Point> pointQueue;

void pushPoint(int x, int y, int step) {
    // printf("pushPoint %d %d %d\n", x, y, step);
    pointFlag[x][y] = 1;
    Point newPoint;
    newPoint.x = x;
    newPoint.y = y;
    newPoint.step = step;
    pointQueue.push(newPoint);
}

int bfs(Point begin, Point end) {
    pointQueue.push(begin);

    pointFlag[begin.x][begin.y] = 1;
    while(pointQueue.size()) {
        Point curPoint = pointQueue.front();
        pointQueue.pop();
        int curX = curPoint.x;
        int curY = curPoint.y;
        int curSteps = curPoint.step;
        // printf("curX %d curY %d curSteps %d\n", curX, curY, curSteps);
        if (curY == N-1) {
            return curSteps;
        }

        if ((curX+1 <= M-1) && (LineSInfo[curY][curX+1] == SEP) && !pointFlag[curX+1][curY]) { // left
            pushPoint(curX+1, curY, curSteps+1);
        }
        if ((curX-1) >= 0 && (LineSInfo[curY][curX-1] == SEP) && !pointFlag[curX-1][curY]) { // right
            pushPoint(curX-1, curY, curSteps+1);
        }
        if ((curY+1) <= N-1 && (LineSInfo[curY+1][curX] == SEP) &&!pointFlag[curX][curY+1]) { // up
            pushPoint(curX, curY+1, curSteps+1);
        }
        if ((curY-1) >= 0 && (LineSInfo[curY-1][curX] == SEP) && !pointFlag[curX][curY-1]) { //down
            pushPoint(curX, curY-1, curSteps+1);
        }
        pointFlag[curX][curY] = 2;
    }
    return -1;
}

void getShortestSep() {
    // printf("getShortestSep\n");
    int minStep = 999999;
    for (int i = 0; i < 2; i++) {
        // for (int j = 0; j < 2; j++) {
            if (beginPoints[i].used) {
                beginPoints[i].step = 0;
                memset(pointFlag, 0, sizeof(pointFlag));
                while(pointQueue.size()) {
                    pointQueue.pop();
                }
                // printf("%d %d %d %d\n", beginPoints[i].x, beginPoints[i].y,
                        // endPoints[j].x, endPoints[j].y);
                int res = bfs(beginPoints[i], endPoints[0]);
                if (res != -1) {
                    minStep = (res + 1) < minStep ? (res + 1) : minStep;
                }
                // printf("%d\n", res);
            }
        // }
    }
    // if (beginPoints[0].used) {
    //     memset(pointFlag, 0, sizeof(pointFlag));
    //     int res = bfs(beginPoints[0], endPoints[0]);
    //     if (res != -1) {
    //         minStep = (res + 1) < minStep ? (res + 1) : minStep;
    //     }
    // }
    printf("%d\n", minStep == 999999 ? -1 : minStep);
}

int main() {
    while(1) {
        scanf("%d %d", &N, &M);
        if (!M && !N) {
            return 0;
        }
        memset(lineSExpandOption, 0, sizeof(lineSExpandOption));
        memset(beginPoints, 0, sizeof(beginPoints));
        memset(endPoints, 0, sizeof(endPoints));
        for (int i = 0; i < N; i++) {
            scanf("%s", LineSInfo[i]);
            int j;
            for (j = M-2; LineSInfo[i][j] != SEP; j--) {
            }
            // printf("%d\n", j);
            LineSInfo[i][j+1] = SEP;
            
            for (j = M-2; LineSInfo[i][j] != SEP; j--) {
                // if (LineSInfo[i][j] == SEP) {
                //     beginPoints[0].x = j;
                //     beginPoints[0].y = 0;
                //     beginPoints[0].used = 1;
                //     break;
                // }
            }
            
            if (i == 0) { // first line begin ponit
                if (j < M-1) { // not first, can be begin
                    beginPoints[0].x = j;
                    beginPoints[0].y = 0;
                    beginPoints[0].used = 1;
                }
                if (j > 0 && (LineSInfo[i][j-1] == SEP)) { // not last-1, can be begin
                    beginPoints[1].x = j-1;
                    beginPoints[1].y = 0;
                    beginPoints[1].used = 1;
                }
            }
            // else if (i == N-1) { // last line end point
            //     if (j < M-1) { // not first, can be begin
            //         endPoints[0].x = j;
            //         endPoints[0].y = N-1;
            //         endPoints[0].used = 1;
            //     }
            //     if (j > 0 && (LineSInfo[i][j-1] == SEP)) { // not last-1, can be begin
            //         endPoints[1].x = j-1;
            //         endPoints[1].y = N-1;
            //         endPoints[1].used = 1;
            //     }
            // }
        }
        getShortestSep();
    }

}


736K    0MS G++

WA了好几次... 各种低级错误

先是M N搞反,数组坐标系搞反,然后是BFS前没有清空queue,

这道题是典型的理解题意难,转化难,求解简单.

一开始没彻底理解题意,以为improvement可以进行数次,然后求最短的seperator,

后来才发现是之进行一次improvement,

最开始本着纯模拟的思路去的,走到一半,发现根本解不了(后来看貌似有人用这种近似思路解出来了,不过感觉已经偏智力题了)

后来再仔细的想,才发现,这道题其实就是一个BFS求从最上到最下的最短路径(路径就是seperator, 路径最短,seperator的vetext也必然最少)

只是怎么拿到这个图G需要些思考,

首先,原来的seperator(简称SEP)里的vetex必然属于G,但是G不止这些点,因为要进行improvement, 任何邻接着S的B都有可能是improve以后变成新的S,

这样,那些邻接S的B也可以加入G中,这样G的vetex就全了,

为了方便后面的BFS,可以先对字符串进行预处理,把符合条件的B变为S。

将整个输入的字符串变为一个二维矩阵C(注意的是,C[Y][X]应该是X Y 坐标系倒置,以为C[i]代表字符串矩阵的某一行,C[i][j]是这一行的第j列,正好X 和 Y颠倒了)

然后就是BFS需要的flag矩阵,用来标示某个节点是否被遍历过,

接下来就是BFS的其实位置,首先,一定是从第一行开始,但是起始点可能会有两个:(一个是improve之前SEP的起始点,一个是前一个起始点右边的B)

这里的细节就是题目规定了起始点不能是第一行的两个端点,因此还要判断这两个点能否满足。

终点更好求,只需要能到达最后一行,就一定是终点了(因为满足了SEP的条件),这里可能也要判断前后端点的问题,不过我没做,貌似这道题的数据也比较弱,按理说只用是否为最后一行判断很可能会得到一个结束点是前后端点的结束点,这是不满足题意的,在这里标记一下这个问题。最保险的是将可能的终点也求出来(也好求,最后一行与上一行的相接处的附近点就是)。

接下来就是对每个起始点进行常规BFS求最短路径了(四个方向,上下左右,没有斜向,根据其值是否是S以及flag 还有 是否越界 来决定是否遍历,注意保存到此节点的路径长度以便最后输出总的路径长度),得到其中的最小值就是SEP的最短长度,+1即可(点比边多1)

这道题是我最怕的类型,转化难,无的放矢,考验的更多是经验积累,以及长期的训练中培养出来的良好直觉.

0 0
原创粉丝点击