1. 程式人生 > >Escape HDU - 3533 bfs+預處理

Escape HDU - 3533 bfs+預處理

做這題複習了幾點

  • bfs 預處理 ,因為判斷某一點能不能走 ,需要提前對每個炮臺進行預處理
  • visit 陣列 剛開始我想我這個 bfs 是從左上角遍歷到右下角,不會回頭,於是剛開始並不想構造 visit 陣列。但是後來發現還是不太好,主要因為這題比較特別,每個狀態三個後繼轉移狀態,如下圖,如果選擇不走,那麼接下來就可能會發生同一個狀態多次入隊的情況。

111
visit 陣列也很好開,因為已經具有最大能量值,直接 visit[x][y][k]
三維陣列開起來也不大。
但是我做題的時候沒想到。

讀題的時候比較費勁,我覺得這題題意比較模糊,大概就是

  1. 城堡會以一定的週期和速度向某個固定方向發射子彈。
  2. 城堡可以擋住到達該點的子彈。
  3. 城堡不能走

相當於閃點 在閃亮的時刻是不能走的。

滿足如下公式,代表不能走

設某個城堡發射子彈的週期為 T,速度為 v,從起點到當前點的時間為 t, 當前點與城堡的距離是 s
如果滿足 s = (t-k*t)*v ,則不能走。

但做這題的時候,我又犯蠢了。
我想用 一維vector 記錄某個點所關聯的所有子彈,但是我用 x * m+y 來定位某個點,這樣會出現 3*4+4 = 4*4 + 0 = 16 兩個不同的點,對映到同一個 index ,這樣顯然錯誤,於是我修改這個對映
#define mmm = 10005
用 x * mmm+y 來做對映,這樣不會出現兩個點對映到一個同一個索引的情況,學藝不精啊。

下附程式碼:

#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>

using namespace std;


#define mmm 10005
vector< vector<int> > num(1001000);
int m,n;
int maxp;
int k;
int maze[105][105];
char dirs[4]={'N','S','E','W'};
int ddi[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};
bool vis[105][105][1005];



struct cas
{
    int t;
    int v;
    int dir;
    int x;
    int y;
};
cas  castle[105];
int re;

struct point
{
    int x;
    int y;
    int t;
};

queue<point>qu;
int dqu[3][2]={{1,0},{0,1},{0,0}};
void bfs()
{
    memset(vis,0,sizeof(vis));
    point st;
    point f;
    point next;
    st.x=0;
    st.y=0;
    st.t=0;
    while(!qu.empty())qu.pop();
    qu.push(st);
    while(!qu.empty())
    {
        f = qu.front();

       // cout<<"***** "<<f.x<<" "<<f.y<<" "<<f.t<<endl;
        qu.pop();
        if(f.x==m&&f.y==n)
        {
            re = f.t;
            break;
        }
        if(f.t > maxp)break;//如果已經大於能量值 就不用再算了

        //向右走
        //向下走
        //停住不動
        for(int i=0;i<3;i++)
        {

            int px =f.x+dqu[i][0];
            int py =f.y+dqu[i][1];
            if(px<0||py<0||px>m||py>n||maze[px][py]==-1||vis[px][py][f.t+1]==1)continue;
            //判斷是否有子彈

            //cout<<"********************* "<<px<<" "<<py<<" "<<f.t+1<<endl;
            int flag=1;
            for(int j=0;j<num[px*mmm+py].size();j++)
            {

                int s = abs(px - castle[num[px*mmm+py][j]].x) + abs(py - castle[num[px*mmm+py][j]].y);
                int a;
                //cout<<"s = "<<s;
                if(s%castle[num[px*mmm+py][j]].v==0)
                {

                  a = s/castle[num[px*mmm+py][j]].v;
                //  cout<<" s/v 整除 "<<a<<endl;
                }
                else continue;  //如果不整除  這個就不用算了

                if((f.t+1)>=a&&(f.t+1 -a)%castle[num[px*mmm+py][j]].t==0) //如果該點有 子彈
                {
                  // cout<<" t- T / a 整除"<<(f.t+1 -a)/castle[num[px*mmm+py][j]].t;
                   flag=0;
                   break;
                }
               // cout<<endl;

            }
             //cout<<endl;
            if(flag==0)
            {
                //cout<<"此處有子彈 "<<endl;
                continue;
            }
            next.t = f.t+1;
            next.x=px;
            next.y=py;
            vis[px][py][f.t+1]=1;
            qu.push(next); //將合格點入棧
        }
    }
    while(!qu.empty())qu.pop();

}
int main()
{
    char tmp;
    int t,v,x,y;

    while(scanf("%d%d%d%d",&m,&n,&k,&maxp)!=EOF)
    {
        for(int i=0;i<=m;i++)
            for(int j=0;j<=n;j++)
            {
                maze[i][j]=0;
            }

        for(int i=0;i<=m;i++)
        for(int j=0;j<=n;j++)
            num[i*mmm+j].clear();


       for(int i=0;i<k;i++)  //輸入城堡的資訊
       {
           getchar();
           scanf("%c %d %d %d %d",&tmp,&castle[i].t,&castle[i].v,&castle[i].x,&castle[i].y);
           //cout<<tmp<<" "<<castle[i].t<<" "<<castle[i].v<<" "<<castle[i].x<<" "<<castle[i].y<<endl;

           maze[castle[i].x][castle[i].y] =-1;  //城堡標記為不可達



           for(int j=0;j<4;j++)
           {
               if(tmp ==dirs[j])
               {
                   castle[i].dir =j;break;
               }
           } //記錄該點的方向

       }


       //預處理
       for(int i=0;i<k;i++)
       {
           //對該點方向上的所有數值  進行更新
           int px = castle[i].x;
           int py = castle[i].y;

           //cout<<"*****"<<px<<" "<<py<<endl;

           while(1)  //獲取新點 進行標記
           {
               maze[px][py]=i;
               px += ddi[castle[i].dir][0];
               py += ddi[castle[i].dir][1];

               //cout<<px<<" "<<py<<endl;


               if(px<0||py<0||px>m||py>n)break;

               if(maze[px][py]==-1)break; //如果遇見城堡

              // cout<<"可以 "<<px*mmm+py<<endl;

               num[px*mmm+py].push_back(i);
           }
           maze[castle[i].x][castle[i].y] =-1;
       }

       re=-1;
       bfs();

       if(re==-1)printf("Bad luck!\n");
       else printf("%d\n",re);
    }
    return 0;
}