1. 程式人生 > >luogu P3716 [CTSC2000]冰原探險

luogu P3716 [CTSC2000]冰原探險

題面

題目背景
傳說中,南極有一片廣闊的冰原,在冰原下藏有史前文明的遺址。整個冰原被橫豎劃分成了很多個大小相等的方格。在這個冰原上有N個大小不等的矩形冰山,這些巨大的冰山有著和南極一樣古老的歷史,每個矩形冰山至少佔據一個方格,且其必定完整地佔據方格。冰山和冰山之間不會重疊,也不會有邊或點相連。以下兩種情況均是不可能出現的:

題目描述
ACM探險隊在經過多年準備之後決定在這個冰原上尋找遺址。根據他們掌握的資料,在這個冰原上一個大小為一格的深洞中,藏有一個由史前人類製作的開關。而唯一可以開啟這個開關的是一個佔據接近一格的可移動的小冰塊。顯然,在南極是不可能有這樣小的獨立冰塊的,所以這塊冰塊也一定是史前文明的產物。他們在想辦法把這個冰塊推到洞裡去,這樣就可以開啟一條通往冰原底部的通道,發掘史前文明的祕密。冰塊的起始位置與深洞的位置均不和任何冰山相鄰。這個冰原上的冰面和冰山都是完全光滑的,輕輕的推動冰塊就可以使這個冰塊向前滑行,直到撞到一座冰山就在它的邊上停下來。冰塊可以穿過冰面上所有沒有冰山的區域,也可以從兩座冰山之間穿過(見下圖)。冰塊只能沿網格方向推動。

請你幫助他們以最少的推動次數將冰塊推入深洞中。

輸入格式:
輸入檔案第一行為冰山的個數N (1<=N<=4000),第二行為冰塊開始所在的方格座標X1,Y1,第三行為深洞所在的方格座標X2,Y2,以下N行每行有四個數,分別是每個冰山所佔的格子左上角和右下角座標Xi1,Yi1,Xi2,Yi2

輸出格式:
輸出檔案僅包含一個整數,為最少推動冰塊的次數。如果無法將冰塊推入深洞中,則輸出0。

說明
1<=N<=4000

思路

關鍵: 
1.map key取2個值更方便 
2.各種判斷條件細節推導

主要思路就是要模擬出冰塊再地圖中直接移動到停下的點的狀態來進行bfs
當前位置(x,y) 目標位置(ex,ey)
上 x1<=x<=x2 && max {y2} -> (x,y2+1)
下 x1<=x<=x2 && min {y1} -> (x,y1-1)
左 y1<=y<=y2 && max {x2} -> (x2+1,y)
右 y1<=y<=y2 && min {x1} -> (x1-1,y)
+ && 冰山的位置要與去的方向一致
1.冰山要在方向的那一邊,與方向一致
2.下個點不能在原地
3.map對座標判重
4.找不到時數值為inf,不能向後走
但不影響判斷答案,因為inf時一定滿足邏輯式
5.可以畫圖,寫出來判斷式後套bfs框架即可
6.每次向後走時直接列舉每一個冰山

程式碼

#include <cstdio>
#include <iostream>
#include <map>
#define re register
#define int long long
using namespace std;

const int inf = 1e9;
const int maxq = 2000005;
int n,bx,by,ex,ey,ans;
struct f {
    int x,y;
    bool operator < (const f &r) const{
        if(x == r.x) return y < r.y;
        return x < r.x;
    }
};
map<f,int> mp;
struct node {
    int x,y,step;
}q[maxq];
int head,tail;
struct point {
    int x1,y1,x2,y2;
}p[5005];
inline void Bfs()
{
    head = 0, tail = 1;
    q[1].x = bx, q[1].y = by, q[1].step = 0;
    mp[(f){bx,by}] = 1;
    while(head < tail)
    {
        head++; if(head >= maxq) head = 1;
        int x = q[head].x, y = q[head].y, step = q[head].step;
//      cout << x <<" " << y << " " << step << endl;
        //上
        int y2 = -inf;
        for(re int i = 1; i <= n; i++)
            if(p[i].x1 <= x && x <= p[i].x2 && p[i].y2 > y2 && p[i].y2 < y)
                y2 = p[i].y2;
        if(x == ex && ey > y2 && ey < y) {
            ans = step + 1;
            return;
        }
        if(y2 != -inf && mp[(f){x,y2+1}] == 0) {
            tail++; if(tail >= maxq) tail = 1;
            q[tail].x = x, q[tail].y = y2 + 1, q[tail].step = step + 1;
            mp[(f){x,y2+1}] = 1;
        }
        //下
        int y1 = inf;
        for(re int i = 1; i <= n; i++)
            if(p[i].x1 <= x && x <= p[i].x2 && p[i].y1 < y1 && p[i].y1 > y)
                y1 = p[i].y1;
        if(x == ex && ey < y1 && ey > y) {
            ans = step + 1;
            return;
        }
        if(y1 != inf && mp[(f){x,y1-1}] == 0) {
            tail++; if(tail >= maxq) tail = 1;
            q[tail].x = x, q[tail].y = y1 - 1, q[tail].step = step + 1;
            mp[(f){x,y1-1}] = 1;
        }
        //左
        int x2 = -inf;
        for(re int i = 1; i <= n; i++)
            if(p[i].y1 <= y && y <= p[i].y2 && p[i].x2 > x2 && p[i].x2 < x)
                x2 = p[i].x2;
        if(y == ey && ex > x2 && ex < x) {
            ans = step + 1;
            return;
        }
        if(x2 != -inf && mp[(f){x2+1,y}] == 0) {
            tail++; if(tail >= maxq) tail = 1;
            q[tail].x = x2 + 1, q[tail].y = y, q[tail].step = step + 1;
            mp[(f){x2+1,y}] = 1;
        }
        //右
        int x1 = inf;
        for(re int i = 1; i <= n; i++)
            if(p[i].y1 <= y && y <= p[i].y2 && p[i].x1 < x1 && p[i].x1 > x)
                x1 = p[i].x1;
        if(y == ey && ex < x1 && ex > x) {
            ans = step + 1;
            return;
        }
        if(x1 != inf && mp[(f){x1-1,y}] == 0) {
            tail++; if(tail >= maxq) tail = 1;
            q[tail].x = x1 - 1, q[tail].y = y, q[tail].step = step + 1;
            mp[(f){x1-1,y}] = 1;
        }
    }
}
signed main()
{
    scanf("%lld", &n);
    scanf("%lld%lld%lld%lld", &bx, &by, &ex, &ey);
    for(int i = 1; i <= n; i++)
        scanf("%lld%lld%lld%lld", &p[i].x1, &p[i].y1, &p[i].x2, &p[i].y2);
    Bfs();
    printf("%lld\n", ans);
    return 0;
}