Kattis Conquest Campaign
題目
https://open.kattis.com/problems/conquestcampaign
給一張 $R \times C$ 的地圖,其中有 $N$ 個可重複的點,標示我們的起點
圖上沒有任何障礙物,在這至多 $N$ 個起點每天我們可以往 上下左右 四個方向擴散,請問最少幾天可以把全部地圖佔領
想法
因為要球最少步驟,所以想到用 BFS 來實作
會影響到未來發展的只有我們佔據了哪些點,所以狀態只需要紀錄被佔領的點座標即可
接下來每次向外四個方向擴散
要注意的是,起點可能重複給,但是實際上重複是沒有意義的
並且為了方便確定當前是不是全部的點都佔領了,我們透過確認當前總共有多少座標被標記在 BFS 的序列當中,那麼重複的點就不應該被重複計算,所以要先拔除
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include<iostream> using namespace std; int R, C, N, S, que[10005][2], dis[105][105]; int dx[] = {-1, 0, 0, 1}; int dy[] = {0, -1, 1, 0}; bool vis[105][105];
void print_all(){ for(int i=1 ; i<=R ; i++){ for(int j=1 ; j<=C ; j++){ if(vis[i][j]) cout<<"*"; else cout<<'.'; } cout<<"\n"; } cout<<"\n"; }
int BFS(){ for(int i=0, j=S, x, y, nx, ny ; i<j ; i++){ x = que[i][0]; y = que[i][1]; if(j == R*C){ return dis[que[j-1][0]][que[j-1][1]]; } for(int k=0 ; k<4 ; k++){ nx = x + dx[k]; ny = y + dy[k]; if(nx <= 0 || nx > R || ny <= 0 || ny > C) continue; if(!vis[nx][ny]){ vis[nx][ny] = true; dis[nx][ny] = dis[x][y] + 1; que[j][0] = nx; que[j][1] = ny; j++; } } } return -1; }
int main(){ for(int i=0 ; i<105 ; i++){ for(int j=0 ; j<105 ; j++){ vis[i][j] = false; } } cin>>R>>C>>N; S=0; for(int i=0, x, y ; i<N ; i++){ cin>>x>>y; if(!vis[x][y]){ que[S][0] = x; que[S][1] = y; vis[x][y] = true; dis[x][y] = 1; S++; } } cout<<BFS()<<"\n"; return 0; }
|
時間複雜度分析
輸入時間複雜度為 $O(N)$
BFS 時間複雜度為 狀態數 $\times$ 操作的數量 $= (nm) \times 4$ ,計為 $O(nm)$
總時間複雜度為 $O(N + nm)$