剛剛上實驗課,榨果汁。。。自覺學不到什麼東西,就來到了機房,看看HDU上的題。一道搜索,其中包含了幾個我從沒想到過的剪枝方法,例如奇偶剪枝、路徑剪枝還有在主函數中的一個剪枝,諸見代碼與註釋,雖然看起來沒什麼用的剪枝沒準會遇到變態的測試數據導致最後的完蛋,所以只要能想到的剪枝就儘量寫上去。
注:這題的代碼來自標程。
/*
Exe.Time Exe.Memory Code Len. Language Author
62MS 1676K 2081 B C++ int9
*/
// PPT上的標程
#define LOCAL
#include <iostream>
#include <cmath>
#include <fstream>
using namespace std;
// 迷宮地圖
// X:牆壁,小狗不能進入
// S:小狗所處位置
// D:迷宮的門
// .:空格
char map[9][9];
int n, m, t, di, dj; // (di, dj):門的位置
bool escape;
int dir[4][2] = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
/*
1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1
*/
void dfs(int si, int sj, int cnt) // 表示在si,sj要求在cnt秒達到門的位置
// cnt 是當前的時間而非上述的註釋
{
int i, temp;
if (si > n || sj > m || si <= 0 || sj <= 0) return;
if (si == di && sj == dj && cnt == t) {
escape = 1;
return;
}
// 此處奇偶剪枝和路徑剪枝
temp = (t - cnt) - abs(si - di) - abs(sj - dj);
if (temp < 0 || temp & 1) return;
for (i = 0; i < 4; i++) {
if (map[si + dir[i][0]][sj + dir[i][1]] != 'X') {
map[si + dir[i][0]][sj + dir[i][1]] = 'X';
dfs(si + dir[i][0], sj + dir[i][1], cnt + 1);
if (escape) return;
// backtrack
map[si + dir[i][0]][sj + dir[i][1]] = '.';
}
}
return;
}
// 到此這個DFS函數已經頗有效率,如果在此main函數中不進行剪枝也是可以的
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
#endif
std::ios::sync_with_stdio(false);
int i, j, si, sj;
while (cin >> n >> m >> t && n && m && t) {
// 此處數據是將要對對某些破爛數據的剪枝,可以刪除掉
int wall = 0;
// Input
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
cin >> map[i][j];
if (map[i][j] == 'S') { si = i; sj = j; }
else if (map[i][j] == 'D') { di = i; dj = j; }
// 對牆數量的剪枝
else if (map[i][j] == 'X') wall++;
}
}
if (n * m - wall <= t) {
cout << "NO" << endl;
continue;
}
escape = 0;
// 上述剪枝完畢,估計也沒多少數據會用到上面這個剪枝,對效率提升不大
map[si][sj] = 'X';
dfs(si, sj, 0);
if (escape) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
同樣是對於矩陣的搜索,這題的矩陣範圍不大,但是測試組數貌似會很多。