1. 程式人生 > >UVa 225 Golygons 題解

UVa 225 Golygons 題解

難點 每天 targe spl 交流 wikipedia code rtx tps

難度:β

建議用時:40 min

關於這道題目的背景在維基百科上有。很神奇。

但是我們的這道題沒有那麽多考慮。上來直接東南西北狂搜一通就好了。

算法很簡單,直接上過程。

首先確定 “東”“南”“西”“北” 對應的英文字母 “e”“s”“w”“n”。

因為題目還說不能後退,所以要把後退的方向也處理出來。”東“對”西“ 等等。

因為出發點在(0,0),又可以往負的方向走,為了用數組存,我們給每個坐標加一個 buf = 105 的東西,保證坐標都非負。

1 blocks[x+buf][y+buf] = 1;

另外因為對一個方向最多只走 buf 個距離,因此在範圍外的障礙物就 pass 掉。

1 if(abs(x) > buf || abs(y) > buf) continue;

下面直接東南西北搜。

技術分享圖片
 1 void dfs(int curDepth, int curX, int curY, int lastDir) {
 2     if(curDepth == lastLenth) {
 3         if(curX == startX && curY == startY) {
 4             output();
 5             total++;
 6         }
 7         return
; 8 } 9 10 if(is_time_to_go_back(curDepth, curX, curY)) return; 11 12 for(int dir = 0; dir <= 3; dir++) { 13 int newX = curX + dx[dir]*(curDepth+1); 14 int newY = curY + dy[dir]*(curDepth+1); 15 16 if(abs(newX) > buf || abs(newY) > buf) continue
; 17 if(block_in_the_way(curX, curY, newX, newY)) continue; 18 if(dir + lastDir == 3 || dir == lastDir) continue; 19 if(vis[newX+buf][newY+buf]) continue; 20 21 vis[newX+buf][newY+buf] = 1; 22 path[curDepth] = dir; 23 dfs(curDepth+1, newX, newY, dir); 24 vis[newX+buf][newY+buf] = 0; 25 } 26 }
View Code

註意這裏的細節:

1 if(dir + lastDir == 3 || dir == lastDir) continue;

回頭看:

1 const char directions[] = {e, n, s, w};

哦!好妙!判斷方向方便很多!小技巧。

作為一到剪枝題,這裏的重點就在剪枝函數 “is_time_to_go_back” 上。

先分析一下。要想在規定的步數走回原點,容易想到要限制不能走太遠。因為走的距離和是有限的。而這裏的距離是以曼哈頓距離為參考的。所以自然要在這方面剪枝。

1 bool is_time_to_go_back(int curDepth, int curX, int curY) {
2     int manhattan_dist = abs(curX) + abs(curY);
3     int remain_dist = S[lastLenth] - S[curDepth];
4     if(remain_dist < manhattan_dist) return true;
5     return false;
6 }

這個 “S” 就是等差數列前 n 項和。計算出還可以走多少曼哈頓距離。

構造 “S” :

1 void init() {
2     S[0] = 0;
3     for(int i = 1; i <= 20; i++) S[i] = S[i-1] + i;
4 }

這題還需判斷有沒有障礙物,上 code :

bool block_in_the_way(int sx, int sy, int tx, int ty) {
    if(sx > tx) swap(sx, tx);
    if(sy > ty) swap(sy, ty);
    for(int x = sx; x <= tx; x++) {
        for(int y = sy; y <= ty; y++) {
            if(blocks[x+buf][y+buf]) return true;
        }
    }
    return false;
}

大概想法就是枚舉路上的每一個點,判斷是不是障礙物。

註意要保證 x 和 y 的遞增。否則枚舉會出問題。

總體過程結束了。

這題回頭看沒有什麽難點,曼哈頓距離就是求絕對值之和。不知道還有沒有更高效的剪枝方法。

不明白的請留言。

如果你對這篇文章感興趣,請關註我,我會定期(每天)更新文章。希望一起交流哈~

2018-01-22 00:02:04 (好晚啊)

UVa 225 Golygons 題解