【upc】穿越——在時間線上的bfs

問題 D: 穿越

時間限制: 2 Sec  內存限制: 128 MB
[提交] [狀態]

題目描述

亞馬遜雨林實在是太大了,小X和他的小弟們進去一會兒就迷路了,然而大雨已經來臨,沖刷了一些道路,小X憑藉他最後的5%的電量給你發來一條求助信息,希望你幫助他們逃出困境……
小X給你發來一張n×m的地圖,每一個點有4種情況。
“0”:此地方可以走。
“1”:此地方不可以走。
“2”:此地方有一種兇惡的野獸。
“3”:此地方爲傳送地域。
野獸會不定時地甦醒過來,此階段該處就不能走。
暴雨會不定時地衝刷一些地區,這些地區從今往後不可以行走,也不可以傳送到。
傳送地域之間可以互相傳送,即可以從一個傳送門傳送到任何一個其他的傳送門。
小X和他的小弟們現在位於(1,1),他們希望在(n,m)點逃出雨林。
他們只能前後左右移動,每移動一次需要花費1個單位的時間,傳送一次需要花費2個單位的時間,也可以選擇不傳送。
注意:若下一秒某地區暴雨即將沖刷/野獸即將醒來,則不可以通行,也不可停留在這個這個地區。
在任意時刻,他們可以選擇不進行任何操作。

 

輸入

第一行兩個整數n,m,表示一張n×m的地圖。
接下來n行,每行m個整數,爲0-3之間的一個數字。
接下來一行一個整數a,表示接下來a行描述暴雨情況。
接下來a行,每行第一個整數爲t,表示此次暴雨在t時刻來臨;第二個整數爲p,表示此次暴雨沖刷了p個地區;接下來p組整數,每組有(x,y)兩個整數,表示(x,y)這個地點被沖刷。(假設暴雨沖刷不需要時間,同一個地點可能被暴雨多次沖刷)
接下來b行,每行前兩個整數爲t1,t2,表示這個野獸在t1-t2時刻是甦醒的。接下來兩個整數x,y,表示野獸位於x,y位置。(保證(x,y)=2)
不保證所有的野獸均會有甦醒的時刻
保證:(1,1)=(n,m)=0且永遠不會被暴雨沖刷。

 

輸出

一行一個整數,即最短逃脫時間。
(保證小X和他的小弟們可以逃脫亞馬遜雨林)

 

樣例輸入 Copy

3 3
0 1 0
2 0 1
3 2 0
2
2 1 3 1
1 1 1 3
1
2 4 2 1

樣例輸出 Copy

4

提示

時刻1,暴雨沖刷了1,3這個位置。
時刻2,暴雨沖刷了3,1這個位置。
時刻2-4,位於(2,1)的野獸甦醒了。
小X與他的小弟們的逃脫路線:
(1,1)->(2,1)->(2,2)->(3,2)->(3,3)
【數據範圍】
對於100%的數據,n≤300,m≤300,t≤10000。


題目大意:中文題意

題目思路:

只要會bfs的大概都知道怎麼做,可能只是細節卡了問題。

原因:我是一個跟着只能跟着新生訓練的蒟蒻,昨晚看到這個題,想了想巨麻煩(就沒有寫)

今天看了看大約1h,1AC

下面分析一下,大致題目思路,是基於時間線上的bfs

時間線上的bfs 基本分爲兩種:

1.單純bfs距離爲1

2.跳躍式bfs

跳躍式bfs基本不成線性關係,但是隻需要記住一點(記錄最早到達的時間即可,因爲時間是增長的,早到達之後你可以等待)

所以鬆弛(更新)條件基本就是最短路的更新條件

看一下這題限制:

1.大雨沖刷之後,該地方不可去(非常重要)

2.猛獸甦醒時間,由於猛獸特定地點,所以甦醒時間只有一段 (這就減少了難度)

3.空地與牆 

4.傳送門 

首先大雨沖刷沒有特定位置,所以走的每一步都需要判斷一下這個地方可不可以走。

因此,需要記錄該地方最早被沖刷過時間,因爲dis數組記錄,最早到達某個點的距離。所以dis[x][y]>vis[x][y]這點便不可以走。

並且這個大雨更新的時間,要在每一步都去判斷。

知道大雨這個之後,剩下的就按部就班的跑bfs:

下一步爲空地:判斷一下是否過去時是否被大雨沖刷

下一步爲傳送門:首先判斷一下是否可以過去,其次判斷一下是否傳送,繼續判斷傳送的目的是否可以到達

下一步爲野獸:首先判斷下一步是否可以過去,其次判斷下一步是否爲野獸甦醒時間,如果野獸未甦醒直接過去。若甦醒,判斷一下野獸結束甦醒時間+1(因爲可以原地不動)是否被大雨沖刷,若沒則可以過去

然後這樣程序便OK了。

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=4e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-9;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int mp[1005][1005];
vector<pair<int,int>>v;
int vis[305][305];
int L[305][305],R[305][305];
int judge(int x,int y){
    if(x<=n&&x>=1&&y<=m&&y>=1) return 1;
    return 0;
}
ll dis[305][305];
void bfs(){
    for(int i=1;i<=n;i++)
        for(int k=1;k<=m;k++)
            dis[i][k]=1e9+7;
    queue<pair<int,int>>q;
    dis[1][1]=0;
    q.push({1,1});
    while(!q.empty()){
        auto p = q.front();q.pop();
        int x = p.first, y = p.second;
        for(int i=0;i<4;i++){
            int mx = x + dx[i],my = y +dy[i];
            if(judge(mx,my)&&mp[mx][my]!=1){///可走
                if(mp[mx][my]==0){///空地
                    if(dis[x][y]+1<vis[mx][my]&&dis[mx][my]>dis[x][y]+1){
                        dis[mx][my]=dis[x][y]+1;
                        q.push({mx,my});
                    }
                }
                else if(mp[mx][my]==2){///野獸fuck
                    int time=dis[x][y]+1;///過去的時間
                    if(time<vis[mx][my]){///大雨fuck
                        int f=0;
                        if(time>=L[mx][my]&&time<=R[mx][my]) f=1;
                        if(f){///不可以過去
                            if(dis[mx][my]>R[mx][my]+1&&R[mx][my]+1<vis[mx][my]){
                                dis[mx][my]=R[mx][my]+1;
                                q.push({mx,my});
                            }
                        }
                        else{
                            if(dis[mx][my]>time){
                                dis[mx][my]=time;
                                q.push({mx,my});
                            }
                        }
                    }
                }
                else if(mp[mx][my]==3){
                    ///不傳送
                    if(dis[x][y]+1<vis[mx][my]&&dis[mx][my]>dis[x][y]+1){///當前不會被沖刷
                        dis[mx][my]=dis[x][y]+1;
                        q.push({mx,my});
                    }
                    ///傳送
                    if(dis[x][y]+1<vis[mx][my]){
                        for(auto pp:v){
                            int tempx=pp.first,tempy=pp.second;
                            if(dis[x][y]+3<vis[tempx][tempy]&&dis[x][y]+3<dis[tempx][tempy]){
                                dis[tempx][tempy]=dis[x][y]+3;
                                q.push({tempx,tempy});
                            }
                        }
                    }
                }
            }
        }
    }
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)
        for(int k=1;k<=m;k++){
            scanf("%d",&mp[i][k]);
            if(mp[i][k]==3) v.push_back({i,k});///傳送地帶
            vis[i][k]=mod;///時間初始化1e9+7
        }
    read(p);
    for(int i=1;i<=p;i++){///大雨沖刷時間r
        int tt;scanf("%d",&tt);
        int a;scanf("%d",&a);
        for(int k=1;k<=a;k++){
            int x,y;scanf("%d%d",&x,&y);
            vis[x][y]=min(vis[x][y],tt);
        }
    }
    read(p);
    for(int i=1;i<=p;i++){
        int t1,t2,x,y;
        scanf("%d%d%d%d",&t1,&t2,&x,&y);
        L[x][y]=t1;
        R[x][y]=t2;
    }
    bfs();
    printf("%lld\n",dis[n][m]);
    return 0;
}
/**
9
9 8 7 4 5 6 3 2 1
**/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章