0 0 0 10 1 0 5 5 8 0 0 0 10 2 0 5 5 8 -2 1 0 5 0 0 0 0
0 2HintIn the first case, Biaoge can walk along the side of building, and no turn needed. In the second case, two buildings block the direct way and Biaoge need to make 2 turns at least.
题目大意:二维平面内给n个矩形,再给2个点,求两点之间所有路径中最少的拐弯次数。
题目分析:好题!乍一看这题跟这道hdu1728一样的。只不过此题要自己把图建出来。矩形很少,坐标很广,所以首先离散化,然后建图。比赛的时候就栽在了建图上。由于此题可以沿着建筑物边缘走(walk along),所以就不能单纯的按格子建图了。如果建筑物的墙有公共部分,即使只有一个点,也是不能通过的,如果建筑物的墙在一条直线上,如果没有公共部分,那么是可以沿着墙直走的。所以考虑将一个格子拆成3*3的格子,如果两面墙有公共部分,那么将中间一行也填墙,如果没有公共部分,则可以走。
这题的精华在建图,图一建就很简单了,随便水过就可以了。我用的记忆化搜索,效率不是很高。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cctype> #include<cmath> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> using namespace std; const int N = 430; const int M = 10000005; const int INF = 0x3f3f3f3f; const double eps = 1e-6; const double PI = acos(-1.0); int g[N][N]; int step[N][N]; int dx[] = {1,-1,0,0}; int dy[] = {0,0,1,-1}; int si,sj,ei,ej; struct node { int x1,y1,x2,y2; }rect[N]; struct nd { int x,y,turn; }ss,now,xh[M]; int hx[N],hy[N]; int nx,ny; int n; int getx(int x) { int l,r,mid; l = 1;r = nx; while(l <= r) { mid = (l + r)>>1; if(hx[mid] == x) return mid; else if(hx[mid] > x) r = mid - 1; else l = mid + 1; } } int gety(int x) { int l,r,mid; l = 1;r = ny; while(l <= r) { mid = (l + r)>>1; if(hy[mid] == x) return mid; else if(hy[mid] > x) r = mid - 1; else l = mid + 1; } } void add(int l1,int r1,int l2,int r2) { int i,j; for(i = l2;i <= r2;i ++) { g[l1][i] = g[r1][i] = 1; if(g[l1 - 2][i] == 1) g[l1 - 1][i] = 1; if(g[r1 - 2][i] == 1) g[r1 + 1][i] = 1; } for(i = l1 + 1;i < r1;i ++) { g[i][l2] = g[i][r2] = 1; if(g[i][l2 - 2] == 1) g[i][l2 - 1] = 1; if(g[i][r2 + 2] == 1) g[i][r2 + 1] = 1; } if(g[r1 + 2][r2 + 2] == 1) g[r1 + 1][r2 + 1] = 1; if(g[l1 - 2][l2 - 2] == 1) g[l1 - 1][l2 - 1] = 1; if(g[l1 - 2][r2 + 2] == 1) g[l1 - 1][r2 + 1] = 1; if(g[r1 + 2][l2 - 2] == 1) g[r1 + 1][l2 - 1] = 1; } void makeg() { int i,j; memset(g,0,sizeof(g)); int l1,r1,l2,r2; si = getx(rect[0].x1); sj = gety(rect[0].y1); ei = getx(rect[0].x2); ej = gety(rect[0].y2); for(i = ei * 3;i >= ei * 3 - 2;i --) { for(j = ej * 3;j >= ej * 3 - 2;j --) g[i][j] = 5; } for(i = 1;i <= n;i ++) { l1 = getx(rect[i].x1); r1 = getx(rect[i].x2); l2 = gety(rect[i].y1); r2 = gety(rect[i].y2); add(l1*3,r1*3-2,l2*3,r2*3-2); } } bool isok(int x,int y) { return (x >= 0 && y >= 0 && x <= nx + nx + nx + 1 && y <= ny + ny + ny + 1); } void bfs() { int head,tail; int i,j; head = tail = 0;//起点不止一个 ss.turn = -1; for(i = si * 3;i >= si * 3 - 2;i --) { for(j = sj * 3;j >= sj * 3 - 2;j --) if(g[i][j] != 1) { ss.x = i; ss.y = j; xh[tail ++] = ss; } } while(head != tail) { now = xh[head ++]; if(head >= M) head -= M; for(i = 0;i < 4;i ++) { ss = now; ss.turn ++; int tx = ss.x + dx[i]; int ty = ss.y + dy[i]; while(isok(tx,ty) && g[tx][ty] != 1) { if(step[tx][ty] > ss.turn) { step[tx][ty] = ss.turn; ss.x = tx; ss.y = ty; if(g[tx][ty] == 5)//直接返回比较快 { printf("%d\n",step[tx][ty]); return; } xh[tail ++] = ss; if(tail >= M) tail -= M; } tx += dx[i]; ty += dy[i]; } } } printf("-1\n"); } void solve() { int i,j; for(i = 0;i <= 3*nx + 1;i ++)//show graph { for(j = 0;j <= 3*ny + 1;j ++) step[i][j] = INF; } bfs(); } int main() { int i,j; while(scanf("%d%d%d%d",&hx[1],&hy[1],&hx[2],&hy[2])) { rect[0].x1 = hx[1]; rect[0].y1 = hy[1]; rect[0].x2 = hx[2]; rect[0].y2 = hy[2]; if(!hx[1] && !hy[1] && !hx[2] && !hy[2]) break; scanf("%d",&n); j = 3; for(i = 1;i <= n;i ++) { scanf("%d%d%d%d",&rect[i].x1,&rect[i].y1,&rect[i].x2,&rect[i].y2); hx[j] = rect[i].x1; hy[j ++] = rect[i].y1; hx[j] = rect[i].x2; hy[j ++] = rect[i].y2; } sort(hx + 1,hx + j); sort(hy + 1,hy + j); nx = 2; for(i = 2;i < j;i ++) if(hx[i] != hx[i - 1]) hx[nx ++] = hx[i]; nx --; ny = 2; for(i = 2;i < j;i ++) if(hy[i] != hy[i - 1]) hy[ny ++] = hy[i]; ny --; makeg(); solve(); } return 0; } //93MS 2140K /* 0 0 3 3 4 2 0 4 2 0 2 2 4 4 2 6 4 2 4 4 6 0 0 0 10 1 0 5 5 8 0 0 0 10 2 0 5 5 8 -2 1 0 5 100 -50 10 20 4 -100 15 -20 30 -5 25 50 100 -30 -30 70 -20 70 -20 120 80 5 -1 60 7 3 1 8 101 888 0 0 49 5 50 0 100 6 0 -1 2 1 3 -1 0 0 1 0 1 1 2 1 -2 3 0 0 0 0 10 1 -3 5 0 8 0 -1 -1 0 9 -3 4 4 5 4 -3 5 5 -2 -3 4 -2 -3 -3 -2 4 -1 2 0 4 1 1 3 3 0 0 1 1 -2 -2 0 0 2 -2 3 0 0 0 0 10 2 0 5 5 8 0 2 4 5 0 0 0 10 2 0 5 5 8 -2 1 0 4 0 0 0 10 2 0 0 5 8 -2 1 0 5 0 0 1 10 0 */ /* ans: -1 0 2 3 2 1 0 5 0 0 2 */