BZOJ 1781 [Usaco2010 Feb]Ice 冰上

BZOJ_1781

    这个题目如果Xi和Yi的范围都很小的话,那么就是个普通的广搜而已,但是现在Xi和Yi的范围超大,于是就多了各种离散化和二分查找。

    其实落脚点也就只有石头周围的4个点,和石头的数量是同级别的,这样每次枚举行走的方向时要快速的找到前面的第一个石头,用二分的话就可以实现比较快速的查找了。

    代码写的巨挫……而且因为代码长了之后就会有些恶心的小bug,找错找了很久,眼泪……

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#define MAXD 20010
#define INF 0x3f3f3f3f
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
int N, B, dis[4 * MAXD], sx, sy, tx, ty;
struct Point
{
    int x, y;
    Point(){}
    Point(int _x, int _y) : x(_x), y(_y){}
    bool operator < (const Point &t) const
    {
        if(x == t.x) return y < t.y;
        return x < t.x;
    }
    bool operator == (const Point &t) const
    {
        return x == t.x && y == t.y;
    }
}b[MAXD], p[4 * MAXD];
void init()
{
    int n = 0;
    scanf("%d%d%d%d", &sx, &sy, &tx, &ty);
    for(int i = 0; i < B; i ++) scanf("%d%d", &b[i].x, &b[i].y);
    std::sort(b, b + B);
    std::unique(b, b + B);
    for(int i = 0; i < B; i ++)
        for(int j = 0; j < 4; j ++)
        {
            int x = b[i].x + dx[j], y = b[i].y + dy[j];
            int k = std::lower_bound(b, b + B, Point(x, y)) - b;
            if(k < B && b[k] == Point(x, y)) continue;
            p[n ++] = Point(x, y);
        }
    std::sort(p, p + n);
    N = std::unique(p, p + n) - p;
}
int xx[MAXD], X, yy[MAXD], Y;
void solve()
{
    for(int i = 0; i < B; i ++) xx[i] = b[i].x, yy[i] = b[i].y;
    std::sort(xx, xx + B), std::sort(yy, yy + B);
    X = std::unique(xx, xx + B) - xx, Y = std::unique(yy, yy + B) - yy;
    std::vector<int> xy[MAXD], yx[MAXD];
    for(int i = 0; i < B; i ++)
    {
        int x = std::lower_bound(xx, xx + X, b[i].x) - xx, y = std::lower_bound(yy, yy + Y, b[i].y) - yy;
        xy[x].push_back(b[i].y), yx[y].push_back(b[i].x);
    }
    for(int i = 0; i < B; i ++)
        std::sort(xy[i].begin(), xy[i].end()), std::sort(yx[i].begin(), yx[i].end());
    int sid = std::lower_bound(p, p + N, Point(sx, sy)) - p, tid = std::lower_bound(p, p + N, Point(tx, ty)) - p;
    std::queue<int> q;
    memset(dis, 0x3f, sizeof(dis[0]) * N);
    dis[sid] = 0;
    q.push(sid);
    while(!q.empty())
    {
        int id = q.front();
        q.pop();
        for(int i = 0; i < 4; i ++)
        {
            int x = p[id].x, y = p[id].y;
            int xid = std::lower_bound(xx, xx + X, x) - xx, yid = std::lower_bound(yy, yy + Y, y) - yy;
            if(i == 0)
            {
                if(xid == X || xx[xid] != x) continue;
                int yid = std::lower_bound(xy[xid].begin(), xy[xid].end(), y) - xy[xid].begin();
                if(yid == xy[xid].size()) continue;
                int nid = std::lower_bound(p, p + N, Point(xx[xid], xy[xid][yid] - 1)) - p;
                if(dis[id] + 1 < dis[nid]) dis[nid] = dis[id] + 1, q.push(nid);
            }
            else if(i == 1)
            {
                if(xid == X || xx[xid] != x) continue;
                int yid = std::lower_bound(xy[xid].begin(), xy[xid].end(), y) - xy[xid].begin() - 1;
                if(yid == -1) continue;
                int nid = std::lower_bound(p, p + N, Point(xx[xid], xy[xid][yid] + 1)) - p;
                if(dis[id] + 1 < dis[nid]) dis[nid] = dis[id] + 1, q.push(nid);
            }
            else if(i == 2)
            {
                if(yid == Y || yy[yid] != y) continue;
                int xid = std::lower_bound(yx[yid].begin(), yx[yid].end(), x) - yx[yid].begin();
                if(xid == yx[yid].size()) continue;
                int nid = std::lower_bound(p, p + N, Point(yx[yid][xid] - 1, yy[yid])) - p;
                if(dis[id] + 1 < dis[nid]) dis[nid] = dis[id] + 1, q.push(nid);
            }
            else
            {
                if(yid == Y || yy[yid] != y) continue;
                int xid = std::lower_bound(yx[yid].begin(), yx[yid].end(), x) - yx[yid].begin() - 1;
                if(xid == -1) continue;
                int nid = std::lower_bound(p, p + N, Point(yx[yid][xid] + 1, yy[yid])) - p;
                if(dis[id] + 1 < dis[nid]) dis[nid] = dis[id] + 1, q.push(nid);
            }
        }
    }
    printf("%d\n", dis[tid]);
}
int main()
{
    while(scanf("%d", &B) == 1)
    {
        init();
        solve();
    }
    return 0;
}

 

原文地址:https://www.cnblogs.com/staginner/p/2740514.html