NOIP普及組 棋盤 題解
阿新 • • 發佈:2020-11-07
NOIP2017 普及組
+++
棋盤
題目描述
有一個m×m的棋盤,棋盤上每一個格子可能是紅色、黃色或沒有任何顏色的。你現在要從棋盤的最左上角走到棋盤的最右下角。
任何一個時刻,你所站在的位置必須是有顏色的(不能是無色的), 你只能向上、 下、左、 右四個方向前進。當你從一個格子走向另一個格子時,如果兩個格子的顏色相同,那你不需要花費金幣;如果不同,則你需要花費 11個金幣。
另外, 你可以花費 22 個金幣施展魔法讓下一個無色格子暫時變為你指定的顏色。但這個魔法不能連續使用, 而且這個魔法的持續時間很短,也就是說,如果你使用了這個魔法,走到了這個暫時有顏色的格子上,你就不能繼續使用魔法; 只有當你離開這個位置,走到一個本來就有顏色的格子上的時候,你才能繼續使用這個魔法,而當你離開了這個位置(施展魔法使得變為有顏色的格子)時,這個格子恢復為無色。
現在你要從棋盤的最左上角,走到棋盤的最右下角,求花費的最少金幣是多少?
輸入格式
第一行包含兩個正整數m, n以一個空格分開,分別代表棋盤的大小,棋盤上有顏色的格子的數量。
接下來的n行,每行三個正整數x, y, c, 分別表示座標為(x,y*)的格子有顏色c。
其中c=1 代表黃色,c=0 代表紅色。 相鄰兩個數之間用一個空格隔開。 棋盤左上角的座標為(1,1),右下角的座標為(m,m)。
棋盤上其餘的格子都是無色。保證棋盤的左上角,也就是(1,1) 一定是有顏色的。
輸出格式
一個整數,表示花費的金幣的最小值,如果無法到達,輸出-1−1。
輸入輸出樣例
輸入 #1複製
5 7 1 1 0 1 2 0 2 2 1 3 3 1 3 4 0 4 4 1 5 5 0
輸出 #1複製
8
分析:
寬搜+剪枝
AC CODE:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const int N = 110, inf = 0x3f3f3f3f; int mp[N][N], f[N][N]; int n, m; int ans = inf; int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; void dfs(int x, int y, int sum, bool frog) { if(x < 1 || y < 1 || x > m || y > m) return; if(sum >= f[x][y]) return; else f[x][y] = sum; if(x==m && y==m) { if(sum < ans) ans = sum; return; } for(int i = 0; i < 4; ++i) { int xx = x + dx[i], yy = y + dy[i]; if(mp[xx][yy]) { if(mp[xx][yy] == mp[x][y]) dfs(xx, yy, sum, false); else dfs(xx, yy, sum+1, false); } else { if(!frog) { mp[xx][yy] = mp[x][y]; dfs(xx, yy, sum+2, true); mp[xx][yy] = 0; // 回溯 } } } } int main() { memset(f, 0x3f, sizeof(f)); scanf("%d %d", &m, &n); for(int i = 1; i <= n; ++i) { int x, y, c; scanf("%d %d %d", &x, &y, &c); mp[x][y] = c + 1; } dfs(1, 1, 0, false); printf("%d\n", ans==inf ? -1 : ans); return 0; }