POJ 2044 Weather Forecast(DFS + 强剪枝)
题意:
有一朵2*2的云朵,和一个4*4的地区。被云层覆盖的区域在当天一定有雨下,云层有4种移动方式 。但是规定在城市或者节日期间希望不要下雨,而且一个地方不能有连续7天没下雨。
思路:
1. 要保证 16 方块中每个方块都在 7 天内被下过雨,因为云块是 2*2 的,所以则只需保证(0,0)(0,1)(1,0)(1,1)四个角落满足上述要求即可;
2. 对于云块,每次有 9 种不同的选择,上下左右,走1步2步,或者不动,针对这 9 种情况,深度搜索即可;
3. 暴力的搜索方法结果就是 TLE,这次采取一种记忆化剪枝的方法,vis[] 标记数组表示:第 k 天,云块处在第 x 位置时,四个角落上面各多少天没被下雨的情况,
如果被递归树某个分支访问过了,则标记为 true。因为 16 方块,访问密集度很高,如果下次再访问,说明重复,则剪枝。这种方法能有效的降低时间;
4. 对于某一天的城市情况,则可以用位运算来表示,只需要一个 int 就能满足需求, 最终代码跑到了 110ms ;
#include <iostream>
#include <algorithm>
using namespace std;
struct ST {
int c00, c01;
int c10, c11;
ST() : c00(0), c01(0), c10(0), c11(0) {}
};
struct POS {
int x, y;
POS(int _x, int _y) : x(_x), y(_y) {}
};
const int dir[9][2] = {{0,0},{-1,0},{-2,0},{0,-1},
{0,-2},{1,0},{2,0},{0,1},{0,2}};
bool vis[370][9][7][7][7][7];
int day[370], N;
inline int getflag(int r) {
return 1 << r;
}
bool judge(int k, const POS& u, const ST& s) {
if (s.c00 == 7 || s.c01 == 7 || s.c10 == 7 || s.c11 == 7)
return false;
int flag = 0;
int x = u.x, y = u.y;
flag |= getflag(4*x + y) | getflag(4*x + y+1);
flag |= getflag(4*(x+1) + y) | getflag(4*(x+1) + y+1);
if (flag & day[k])
return false;
if (vis[k][3*x+y][s.c00][s.c01][s.c10][s.c11])
return false;
vis[k][3*x+y][s.c00][s.c01][s.c10][s.c11] = true;
return true;
}
bool dfs(int k, const POS& u, const ST& state) {
if (k == N)
return true;
ST s = state;
s.c00 += 1, s.c01 += 1;
s.c10 += 1, s.c11 += 1;
if (u.x == 0 && u.y == 0)
s.c00 = 0;
else if (u.x == 0 && u.y == 2)
s.c01 = 0;
else if (u.x == 2 && u.y == 0)
s.c10 = 0;
else if (u.x == 2 && u.y == 2)
s.c11 = 0;
if (!judge(k, u, s))
return false;
for (int i = 0; i < 9; i++) {
int x = u.x + dir[i][0];
int y = u.y + dir[i][1];
if (0 <= x && x < 3 && 0 <= y && y < 3) {
if (dfs(k + 1, POS(x, y), s))
return true;
}
}
return false;
}
int main() {
while (scanf("%d", &N) && N) {
for (int i = 0; i < N; i++) {
day[i] = 0;
for (int j = 0; j < 16; j++) {
int x;
scanf("%d", &x);
day[i] <<= 1;
day[i] |= x;
}
memset(vis[i], false, sizeof(vis[i]));
}
ST s;
if (dfs(0, POS(1, 1), s))
printf("1\n");
else
printf("0\n");
}
return 0;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------