日期:2025年3月4日
ZeroJudge 題目連結:f340. 4.俄羅斯方塊 (Tetris)
解題想法
這題要先寫出各種指令對應的操作,還要檢查方塊是否在邊界使方塊無法旋轉,寫起來很容易出錯。
Python 程式碼
使用時間約為 24 ms,記憶體約為 5.1 MB,通過測試。
# 方向:0 朝右,1 朝下,2 朝左,3 朝上
def bottom(x, y, d): # 檢查是否已觸底,輸入錨點座標 (x, y),方向 d
if d == 3: return y >= n-1 # 朝上,回傳 y 是否大於等於 n-1
else: return y+1 >= n-1 # 其它方向,回傳 y+1 是否大於等於 n-1
def zero(x, y, d): # 指令 0,方向 d,向下移一格
return x, y+1, d
def one(x, y, d): # 指令 1,輸入錨點座標 (x, y),方向 d,向右、向下移一格
# 如果「方向朝右、下、上且 x+1 小於 m-1」或是「方向朝左且 x 小於 m-1」,可以向右移一格
if (d in (0, 1, 3) and x+1 < m-1) or (d == 2 and x < m-1): x += 1
return x, y+1, d
def two(x, y, d): # 指令 2,輸入錨點座標 (x, y),方向 d,向左、向下移一格
# 如果「方向朝下、左、上且 x-1 大於 0」或是「方向朝右且 x 大於 0」,可以向左移一格
if (d in (1, 2, 3) and x-1 > 0) or (d == 0 and x > 0): x -= 1
return x, y+1, d
def three(x, y, d): # 指令 3,輸入錨點座標 (x, y),方向 d,置底
if d == 3: return x, n-1, d # 朝上,錨點 y = n-1
else: return x, n-2, d # 其它方向,錨點 y = n-2
def four(x, y, d): # 指令 4,輸入錨點座標 (x, y),方向 d,右旋
if d == 2 and x == m-1: d = 2 # 朝左且 x 等於 m-1,不能右旋
elif d == 0 and x == 0: d = 0 # 朝右且 x 等於 0,不能右旋
else: d = (d+1)%4 # 右旋
if bottom(x, y, d): return x, y, d # 如果已經觸底,回傳 x, y, d
return x, y+1, d # 否則回傳 x, y+1, d
### 初始化 ###
m, n = map(int, input().split()) # 畫面寬度 m、高度 n
s = int(input()) # 指令數量 s
arr = list(map(int, input().split())) # 指令
if m%2 == 1: x = (m+1)//2 - 1 # 如果 m 是奇數
else: x = m//2 - 1 # 如果 m 是偶數
y = 0 # 初位置 y 座標
d = 1 # 方向朝下
### 依照指令改變方塊的位置及方向 ###
for a in arr: # 依序由 arr 讀取指令 a
if a == 0: x, y, d = zero(x, y, d) # 指令 0
elif a == 1: x, y, d = one(x, y, d) # 指令 1
elif a == 2: x, y, d = two(x, y, d) # 指令 2
elif a == 3: x, y, d = three(x, y, d); break # 指令 3,執行完畢後中止迴圈
else: x, y, d = four(x, y, d) # 指令 4
if bottom(x, y, d): break # 如果已經觸底中止迴圈
### 畫出最後的地圖 ###
grid = [[0]*m for _ in range(n)] # 地圖
if d == 0: # 朝右
grid[y-1][x] = grid[y][x] = grid[y+1][x] = grid[y][x+1] = 1
elif d == 1: # 朝下
grid[y][x-1] = grid[y][x] = grid[y][x+1] = grid[y+1][x] = 1
elif d == 2: # 朝左
grid[y-1][x] = grid[y][x] = grid[y+1][x] = grid[y][x-1] = 1
else: # 朝上
grid[y][x-1] = grid[y][x] = grid[y][x+1] = grid[y-1][x] = 1
for g in grid: print(*g, sep='') # 印出地圖
C++ 程式碼
使用時間約為 3 ms,記憶體約為 392 kB,通過測試。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 方向:0 朝右,1 朝下,2 朝左,3 朝上
struct Block { // 方塊錨點位置 (x, y),方向 d
int x, y, d;
};
int m, n; // 畫面寬度 m、高度 n
bool bottom(Block b) { // 檢查是否已觸底,輸入方塊物件
if (b.d == 3) return b.y >= n-1; // 朝上,回傳 y 是否大於等於 n-1
else return b.y+1 >= n-1; // 其它方向,回傳 y+1 是否大於等於 n-1
}
Block zero(Block b) { // 指令 0,輸入方塊物件,向下移一格
Block t; t.x = b.x; t.y = b.y + 1; t.d = b.d;
return t;
}
Block one(Block b) { // 指令 1,輸入方塊物件,向右、向下移一格
// 如果「方向朝右、下、上且 x+1 小於 m-1」或是「方向朝左且 x 小於 m-1」,可以向右移一格
Block t; t.x = b.x; t.y = b.y + 1; t.d = b.d;
if (((b.d == 0 || b.d == 1 || b.d == 3) && b.x+1 < m-1) || (b.d == 2 && b.x < m-1)) t.x++;
return t;
}
Block two(Block b) { // 指令 2,輸入方塊物件,向左、向下移一格
// 如果「方向朝下、左、上且 x-1 大於 0」或是「方向朝右且 x 大於 0」,可以向左移一格
Block t; t.x = b.x; t.y = b.y + 1; t.d = b.d;
if (((b.d == 1 || b.d == 2 || b.d == 3) && b.x-1 > 0) || (b.d == 0 && b.x > 0)) t.x--;
return t;
}
Block three(Block b) { // 指令 3,輸入方塊物件,置底
Block t;
if (b.d == 3) { // 朝上,錨點 y = n-1
t.x = b.x; t.y = n-1; t.d = b.d;
} else { // 其它方向,錨點 y = n-2
t.x = b.x; t.y = n-2; t.d = b.d;
}
return t;
}
Block four(Block b) { // 指令 4,輸入方塊物件,右旋
Block t;
if (b.d == 2 && b.x == m-1) t.d = 2; // 朝左且 x 等於 m-1,不能右旋
else if (b.d == 0 && b.x == 0) t.d = 0; // 朝右且 x 等於 0,不能右旋
else t.d = (b.d+1)%4; // 右旋
if (bottom(t)) {
return t; // 如果已經觸底,回傳 t
} else { // 否則回傳 y+1 之後的 t
t.x = b.x; t.y = b.y + 1;
return t;
}
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
/* 初始化 */
cin >> m >> n; // 畫面寬度 m、高度 n
int s; cin >> s; // 指令數量 s
vector<int> arr (s); // 指令
for(int i=0; i<s; i++) cin >> arr[i];
int x, y = 0; // 方塊的初位置 (x, 0)
if (m%2 == 1) x = (m+1)/2 - 1; // 如果 m 是奇數
else x = m/2 - 1; // 如果 m 是偶數
/* 依照指令改變方塊的位置及方向 */
Block b; b.x = x; b.y = y; b.d = 1;
for(int a : arr) { // 依序由 arr 讀取指令 a
if (a == 0) b = zero(b); // 指令 0
else if (a == 1) b = one(b); // 指令 1
else if (a == 2) b = two(b); // 指令 2
else if (a == 3) { b = three(b); break; } // 指令 3,執行完畢後中止迴圈
else b = four(b); // 指令 4
if (bottom(b)) break; // 如果已經觸底中止迴圈
}
/* 畫出最後的地圖 */
vector<vector<int>> grid (n, vector<int> (m, 0)); // 地圖
if (b.d == 0) grid[b.y-1][b.x] = grid[b.y][b.x] = grid[b.y+1][b.x] = grid[b.y][b.x+1] = 1; // 朝右
else if (b.d == 1) grid[b.y][b.x-1] = grid[b.y][b.x] = grid[b.y][b.x+1] = grid[b.y+1][b.x] = 1; // 朝下
else if (b.d == 2) grid[b.y-1][b.x] = grid[b.y][b.x] = grid[b.y+1][b.x] = grid[b.y][b.x-1] = 1; // 朝左
else grid[b.y][b.x-1] = grid[b.y][b.x] = grid[b.y][b.x+1] = grid[b.y-1][b.x] = 1; // 朝上
for(int i=0; i<n; i++) { // 印出地圖
for(int j=0; j<m; j++) cout << grid[i][j];
cout << "\n";
}
return 0;
}
沒有留言:
張貼留言