hdu 4444 Walk (離散化+建圖+bfs+三維判重 好題)

來源:互聯網
上載者:User
Walk

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1142    Accepted Submission(s): 195Problem DescriptionBiaoge 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. 

InputThere 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. 

OutputFor 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 1010 5 5 80 0 0 1020 5 5 8-2 1 0 50 0 0 0
 

Sample Output

02HintIn 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. 
 

Source2012 Asia JinHua Regional Contest感想:哇哈哈,這題搞了一天終於搞出來啦!  早上開始研究一個人的代碼(很簡潔,風格很好),研究了一個早上,思想都懂了,然後下午開始自己寫,寫出來後測別人貼的資料,發現最後一組資料怎麼也過不了,又仔細研究了一會,發現這種思路就是錯的。 我
X_X ,當時就有砸電腦的衝動了,白白浪費我我這麼長時間。   ps:這題地區賽時資料水了,所以有些字碼頁就水過了,所以提供的解題報告有些就是錯的。然後下午又重新開始搞,看了一個人的思路覺得很正確,然後晚上就開始按照這種思路寫,寫出來了也是各種debug,各種改代碼,最後終於AC了,那叫一個爽呀!
題意:二維平面內給n個矩形,再給2個點,求兩點之間所有路徑中最少的拐彎次數。

思路:離散化矩形,因為矩形邊界可以走,所以還是有點麻煩的,將一個1*1的方格看做3*3的方格後就好處理了。最重要的問題就是該怎樣表示矩形。我是這樣做的:將矩形覆蓋地區塗黑(標記為1),注意不能全部塗黑,不然邊界也不能走了,每次將矩形塗黑時,要將矩形左邊界+1,右邊界-1,上下界也同樣。這樣矩形的邊界就可以走了。但是這又會出現另一種情況,就是有兩個相鄰的矩形時,它們的邊界是不能走的。我們可以這樣判斷一個點能否往上走:如果它所在的3*3的方格的上方的點左邊和右邊都是黑的,那麼它就不能往上走。(下、左、右同理) 最糾結的就是拐點處了(“L”型地區)
這個就必須特判了,有8種情況,自己把情況想清楚了再寫。圖建好了之後就和“hdu 1728” 一樣了,就不多說了。注意:1.邊界情況很重要 橫邊界能橫著走,不能豎著走,豎邊界同理。2.‘L’型地區要特殊處理,有8種情況,要好好分析。3.一個點可能走多次,不能簡單的二維判重,要加上方向。(比如我貼的最後一組資料)ps:思路來源於:http://blog.csdn.net/asdfgh0308/article/details/8125832        資料來源於:http://blog.csdn.net/ophunter/article/details/9768855#comments自己方便debug,加了幾個show函數,加了幾個中間輸出,代碼變長了一點。
代碼:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define maxn 350using namespace std;int n,m,ans;int sx,sy,ex,ey;int x[maxn],y[maxn];int xx[maxn],yy[maxn];int mp[maxn][maxn];int up[maxn][maxn],down[maxn][maxn];int le[maxn][maxn],ri[maxn][maxn];int dx[]= {-3,3,0,0};int dy[]= {0,0,-3,3};bool vis[maxn][maxn][4];  // 三維判重 x+y+方向struct Node{    int l,d,r,u;} rect[maxn];struct node{    int mx,my;    int d,cnt;   // 方向 轉向次數} cur,now,q[maxn*maxn];void showxxyy()  // 輸出離散化後的x y{    int i,j;    printf("xx:\n");    for(i=1; i<=m; i++)    {        printf("%d ",xx[i]);    }    printf("\n");    printf("yy:\n");    for(i=1; i<=m; i++)    {        printf("%d ",yy[i]);    }    printf("\n");}void showmap()  // 輸出地圖{    int i,j;    printf("showmap:\n");    printf("       1  2  3  4  5  6  7  8  9  10 11 12 \n");    for(i=1; i<=3*xx[m]; i++)    {        printf("%3d: ",i);        for(j=1; j<=3*yy[m]; j++)        {            printf("%d",mp[i][j]);        }        printf("\n");    }}void disc()   // 離散化{    int i,j;    m=2*n+2;    sort(x+1,x+m+1);    xx[1]=1;    for(i=2; i<=m; i++)    {        if(x[i]==x[i-1]) xx[i]=xx[i-1];        else xx[i]=xx[i-1]+1;    }    sort(y+1,y+m+1);    yy[1]=1;    for(i=2; i<=m; i++)    {        if(y[i]==y[i-1]) yy[i]=yy[i-1];        else yy[i]=yy[i-1]+1;    }//    showxxyy();}int find(int v,int k)   // 找到離散化對應的點{    int i,j;    if(k)    {        for(i=1; i<=m; i++)        {            if(y[i]==v) return yy[i];        }    }    else    {        for(i=1; i<=m; i++)        {            if(x[i]==v) return xx[i];        }    }}void buildgraph()  // 將1*1的方格轉化為3*3的方格後建圖{    int i,j,ni,nj,k,l,d,r,u;    memset(mp,0,sizeof(mp));    memset(up,1,sizeof(up));    memset(down,1,sizeof(down));    memset(le,1,sizeof(le));    memset(ri,1,sizeof(ri));    for(k=1; k<=n; k++)  // 將矩形在地圖上塗黑    {        l=3*find(rect[k].l,0)+1;        d=3*find(rect[k].d,1)+1;        r=3*find(rect[k].r,0)-1;        u=3*find(rect[k].u,1)-1;//        printf("l:%d d:%d r:%d u:%d\n",l,d,r,u);        for(i=l; i<=r; i++)        {            for(j=d; j<=u; j++)            {                mp[i][j]=1;            }        }    }    for(i=1; i<=xx[m]; i++)  // 記錄是否能走 是否是‘L’型地區    {        for(j=1; j<=yy[m]; j++)        {            ni=3*i;            nj=3*j;            if(mp[ni-1][nj-1]&&mp[ni+1][nj+1])            {                up[ni][nj]=down[ni][nj]=le[ni][nj]=ri[ni][nj]=-1;            }            else if(mp[ni+1][nj-1]&&mp[ni-1][nj+1]) up[ni][nj]=down[ni][nj]=le[ni][nj]=ri[ni][nj]=-2;            if(mp[ni-1][nj-1]&&mp[ni-1][nj+1]) up[ni][nj]=0;            if(mp[ni+1][nj-1]&&mp[ni+1][nj+1]) down[ni][nj]=0;            if(mp[ni-1][nj-1]&&mp[ni+1][nj-1]) le[ni][nj]=0;            if(mp[ni-1][nj+1]&&mp[ni+1][nj+1]) ri[ni][nj]=0;        }    }//    showmap();}bool bfs() // 圖建好了 就是簡單的bfs了{    int i,j,nx,ny,nd,ncnt,tx,ty;    int head=0,tail=-1;    memset(vis,0,sizeof(vis));    sx=3*find(sx,0);    sy=3*find(sy,1);    ex=3*find(ex,0);    ey=3*find(ey,1);//    printf("sx:%d sy:%d ex:%d ey:%d\n",sx/3,sy/3,ex/3,ey/3);    cur.mx=sx;    cur.my=sy;    cur.d=-1;    cur.cnt=0;    vis[sx][sy][0]=vis[sx][sy][1]=vis[sx][sy][2]=vis[sx][sy][3]=1;    q[++tail]=cur;    while(head<=tail)    {        now=q[head];        head++;        nx=now.mx;        ny=now.my;        nd=now.d;        ncnt=now.cnt;//        printf("nx:%d ny:%d nd:%d ncnt:%d\n",nx/3,ny/3,nd,ncnt);        if(nx==ex&&ny==ey)        {            ans=ncnt;            return true ;        }        for(i=0; i<4; i++)        {            if(i==0&&!up[nx][ny]||i==1&&!down[nx][ny]||i==2&&!le[nx][ny]||i==3&&!ri[nx][ny]) continue ; // 判斷是否能往這個方向走            if(up[nx][ny]==-1)    // 對‘L’型地區特判            {                if(i==0&&(nd==0||nd==3)) continue ;                else if(i==1&&(nd==1||nd==2)) continue ;                else if(i==2&&(nd==2||nd==1)) continue ;                else if(i==3&&(nd==3||nd==0)) continue ;            }            else if(up[nx][ny]==-2)            {                if(i==0&&(nd==0||nd==2)) continue ;                else if(i==1&&(nd==1||nd==3)) continue ;                else if(i==2&&(nd==2||nd==0)) continue ;                else if(i==3&&(nd==3||nd==1)) continue ;            }            tx=nx+dx[i];            ty=ny+dy[i];            while(tx>=1&&tx<=3*xx[m]&&ty>=1&&ty<=3*yy[m]&&!mp[tx][ty]) // 每次向一個方向搜尋            {                if(!vis[tx][ty][i])                {                    vis[tx][ty][i]=1;                    cur.mx=tx;                    cur.my=ty;                    cur.d=i;                    cur.cnt=ncnt;                    if(cur.d!=nd&&nd!=-1) cur.cnt++;                    q[++tail]=cur;                }                if(i==0&&!up[tx][ty]||i==1&&!down[tx][ty]||i==2&&!le[tx][ty]||i==3&&!ri[tx][ty]) break ;                if(up[tx][ty]==-1||up[tx][ty]==-2) break ;                tx+=dx[i];                ty+=dy[i];            }        }    }    return false ;}int main(){    int i,j;    int x1,y1,x2,y2,l,d,r,u;    while(scanf("%d%d%d%d",&sx,&sy,&ex,&ey),sx||sy||ex||ey)    {        scanf("%d",&n);        for(i=1; i<=n; i++)        {            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);            l=min(x1,x2);            r=max(x1,x2);            d=min(y1,y2);            u=max(y1,y2);            x[i]=rect[i].l=l;            x[i+n]=rect[i].r=r;            y[i]=rect[i].d=d;            y[i+n]=rect[i].u=u;        }        x[2*n+1]=sx;        x[2*n+2]=ex;        y[2*n+1]=sy;        y[2*n+2]=ey;        disc();        buildgraph();        if(bfs()) printf("%d\n",ans);        else printf("-1\n");    }    return 0;}/*// 繞路   21 1 1 410 2 2 3// 直走  01 1 1 413 3 4 5// 沿著邊直走  00 1 0 720 2 2 3-1 4 0 5// 沿著邊直走  00 1 0 720 2 2 30 3 2 4// 無法穿過縫隙,繞路   20 1 0 720 2 2 3-1 3 0 5// 無法到達  -10 0 5 54-1 1 1 21 -1 2 1-1 -1 1 -2-1 1 -2 -1// 同點經過兩次。  51 3 4 110-1 -1 3 23 -1 7 07 -1 11 39 3 11 7-1 7 11 90 5 4 7-1 2 0 72 2 4 34 3 5 45 4 8 6*/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.