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; }