现在的位置: 首页 > 综合 > 正文

hdu4444Walk(离散化+建图+记忆化搜索)

2014年09月05日 ⁄ 综合 ⁄ 共 4775字 ⁄ 字号 评论关闭

Walk

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1130    Accepted Submission(s): 185


Problem Description
Biaoge is planning to walk to amusement park. The city he lives can be abstracted as a 2D plane. Biaoge is at (x1, y1) and the amusement park is at (x2, y2). There are also some rectangle buildings. Biaoge can only walk parallel to the coordinate axis. Of course
Biaoge can’t walk across the buildings.
What’s the minimum number of turns Biaoge need to make?


As the figure above shows, there are 4 buildings and Biaoge need to make at least 3 turns to reach the amusement park(Before walking he can chose a direction freely). It is guaranteed that all the buildings are parallel to the coordination axis. Buildings may
contact but overlapping is impossible. The amusement park and Biaoge’s initial positions will not contact or inside any building.
 


Input
There are multiple test case.
Each test case contains several lines.
The first line contains 4 integers x1, y1, x2, y2 indicating the coordinate of Biaoge and amusement park.
The second line contains one integer N(0≤N≤50), indicating the number of buildings.
Then N lines follows, each contains 4 integer x1, y1, x2, y2, indicating the coordinates of two opposite vertices of the building.
Input ends with 0 0 0 0, you should not process it.
All numbers in the input range from -108 to 108.
 


Output
For each test case, output the number of least turns in a single line. If Biaoge can’t reach the amusement park, output -1 instead.
 


Sample Input
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
 


Sample Output
0 2
Hint
In 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
*/

抱歉!评论已关闭.