USACO 2.4.2 Overfencing

题意是给你一个迷宫,有两个出口,找出最长的从迷宫内任意一点到出口的最短距离。

一开始想到的是dijkstra,在两个出口分别运行一次,取每个点到两个出口距离中最短的,再去其中最大的即可。

然后想到其实分别从两个出口作BFS,标注每个点的距离即可。

/*
ID: xjtuacm1
PROG: maze1
LANG: C++
*/
#include<iostream>
#include<stack>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
const int W = 38;
const int H = 100;
const int INF = 0x3f3f3f3f;

const int dir[4] = { 1, 2, 4, 8};

int stage[H][W];
int color[H][W];
int h, w;

struct Point
{
    int x, y;
    Point(int xx = 0, int yy = 0) :x(xx), y(yy) {}
    bool operator<(const Point& rhs) const
    {
        if(x == rhs.x)
            return y < rhs.y;
        return x < rhs.x;
    }

    bool connect(int d) const
    {
        return !(stage[x][y] & dir[d]);
    }

    Point next(int d) const
    {
        switch(dir[d])
        {
        case 1:
            return Point(x, y-1);
        case 2:
            return Point(x-1, y);
        case 4:
            return Point(x, y+1);
        case 8:
            return Point(x+1, y);
        }
        return Point();
    }
};

void init()
{
    for(int i = 0; i!= h; i++)
        for(int j = 0; j!= w; j++)
        {
            stage[i][j] = 0xF;
            color[i][j] = INF;
        }
}

void addEdge(const Point& u, const Point& v)
{
    const Point& a = u<v ? u : v;
    const Point& b = u<v ? v : u;
    if(a.x == b.x)
    {
        stage[a.x][a.y] ^= 1<<2;
        stage[b.x][b.y] ^= 1;
    }
    if(a.y == b.y)
    {
        stage[a.x][a.y] ^= 1<<3;
        stage[b.x][b.y] ^= 1<<1;
    }
}

void bfs(const Point& src)
{
    color[src.x][src.y] = 1;
    queue<pair<Point, int> > que;
    que.push(make_pair(src, 1));

    while(!que.empty())
    {
        Point pt = que.front().first;
        int dis = que.front().second;
        que.pop();

        for(int i = 0; i!= 4; i++)
        {
            if(pt.connect(i))
            {
                Point nxt = pt.next(i);
                if(dis+1 < color[nxt.x][nxt.y])
                {
                    color[nxt.x][nxt.y] = dis + 1;
                    que.push(make_pair(nxt, color[nxt.x][nxt.y]));
                }
            }
        }
    }
}

int main(int argc, char *argv[])
{
    freopen("maze1.in", "r", stdin);
#ifndef USACO
    freopen("maze1.out", "w", stdout);
#endif // USACO


    scanf("%d %d", &w, &h); getchar();
    init();

    Point extCell[2];
    int extCnt = 0;

    char line[2*W + 2];

    // first line
    gets(line);
    for(int i = 0; i!= strlen(line); i++)
    {
        if(line[i] == ' ')
            extCell[extCnt++] = Point(0, (i - 1) / 2);
    }
    for(int i = 0; i!= 2 * h - 1; i++)
    {
        gets(line);
        if(i & 1)
        {
            for(int j = 0; j != strlen(line); j++)
            {
                if(line[j] == ' ')
                {
                    addEdge(Point((i-1)/2, (j-1)/2),
                            Point((i+1)/2, (j-1)/2) );
                }
            }
        }
        else
        {
            if(line[0] == ' ')
            {
                extCell[extCnt++] = Point(i / 2, 0);
            }
            if(line[strlen(line) - 1] == ' ')
            {
                extCell[extCnt++] = Point(i / 2, w - 1);
            }
            for(int j = 2; j< strlen(line) - 1; j+= 2)
            {
                if(line[j] == ' ')
                {
                    addEdge(Point(i/2, j/2 - 1),
                            Point(i/2, j/2) );
                }
            }
        }
    }
    // last line
    gets(line);
    for(int i = 0; i!= strlen(line); i++)
    {
        if(line[i] == ' ')
            extCell[extCnt++] = Point(h-1, (i - 1) / 2);
    }

    bfs(extCell[0]);
    bfs(extCell[1]);

    int m = 0;
    for(int i = 0; i!= h; i++)
        for(int j = 0; j!= w; j++)
        m = max(m, color[i][j]);

    printf("%d\n", m);


    return 0;
}