Escape HDU - 3533 bfs+預處理
阿新 • • 發佈:2018-11-19
做這題複習了幾點
- bfs 預處理 ,因為判斷某一點能不能走 ,需要提前對每個炮臺進行預處理
- visit 陣列 剛開始我想我這個 bfs 是從左上角遍歷到右下角,不會回頭,於是剛開始並不想構造 visit 陣列。但是後來發現還是不太好,主要因為這題比較特別,
每個狀態
有三個後繼轉移狀態
,如下圖,如果選擇不走,那麼接下來就可能會發生同一個狀態多次入隊的情況。
visit 陣列也很好開,因為已經具有最大能量值,直接 visit[x][y][k]
三維陣列開起來也不大。
但是我做題的時候沒想到。
讀題的時候比較費勁,我覺得這題題意比較模糊,大概就是
- 城堡會以一定的週期和速度向某個固定方向發射子彈。
- 城堡可以擋住到達該點的子彈。
- 城堡不能走
相當於閃點
在閃亮的時刻是不能走的。
滿足如下公式,代表不能走
設某個城堡發射子彈的週期為 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; }