搜索 |
较麻烦的搜索题目训练 |
poj1069,poj3322,poj1475,poj1924,poj2049,poj3426 |
广搜的状态优化 |
poj1768,poj1184,poj1872,poj1324,poj2046,poj1482 |
|
深搜的优化 |
poj3131,poj2870,poj2286 |
较麻烦的搜索题目训练
poj 3322
感觉这题应该归类到模拟题。。。bfs&&priority_queue直接模拟就行。昨晚写了一个版本,因为状态记录的太多了,MLE一次。发现总共有三种形状,每种形状可以用一个坐标加一个标号表示。比如约定立着的用(x, y, 0)表示,横着的为(x, y), (x, y + 1)用(x, y, 1)表示,竖着的为(x, y),(x + 1, y)用(x, y, 2)表示。然后直接模拟出每种形状可以转移到的形状,bfs。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> //#include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("data.out", "w", stdout); typedef long long LL; const double eps = 1e-8; const double PI = acos(-1.0); const int inf = ~0u>>2; using namespace std; const int maxn = 550; struct Point { int x, y; int f; Point() {} Point(int a, int b, int f) : x(a), y(b), f(f) {} bool operator == (const Point p) const { return (x == p.x && y == p.y && f == p.f); } }; struct node { Point now; int dis; node() {} node(Point a, int b) : now(a), dis(b) {} bool operator < (const node& cmp) const { return dis > cmp.dis; } }; char mp[maxn][maxn]; bool vis[maxn][maxn][3]; int R, C; Point s1, s2, tg; bool inmap(int x, int y) { if(x < 0 || x >= R || y < 0 || y >= C) return false; return true; } bool check(int x, int y) { if(inmap(x, y) && mp[x][y] != '#') return true; return false; } priority_queue<node> q; int bfs() { while(!q.empty()) q.pop(); CL(vis, false); q.push(node(s1, 0)); vis[s1.x][s1.y][s1.f] = true; node u; int x, y; while(!q.empty()) { u = q.top(); q.pop(); //printf("%d %d %d %d\n", u.now.x, u.now.y, u.now.f, u.dis); if(u.now == tg) { return u.dis; } x = u.now.x; y = u.now.y; if(u.now.f == 0) { //u if(check(x-2, y) && check(x-1, y) && !vis[x-2][y][2]) { vis[x-2][y][2] = true; q.push(node(Point(x-2, y, 2), u.dis + 1)); } //d if(check(x+1, y) && check(x+2, y) && !vis[x+1][y][2]) { vis[x+1][y][2] = true; q.push(node(Point(x+1, y, 2), u.dis + 1)); } //l if(check(x, y-2) && check(x, y-1) && !vis[x][y-2][1]) { vis[x][y-2][1] = true; q.push(node(Point(x, y-2, 1), u.dis + 1)); } //r if(check(x, y+1) && check(x, y+2) && !vis[x][y+1][1]) { vis[x][y+1][1] = true; q.push(node(Point(x, y+1, 1), u.dis + 1)); } } else if(u.now.f == 1) { //u if(check(x-1, y) && check(x-1,y+1) && !vis[x-1][y][1]) { vis[x-1][y][1] = true; q.push(node(Point(x-1,y,1), u.dis + 1)); } //d if(check(x+1,y) && check(x+1,y+1) && !vis[x+1][y][1]) { vis[x+1][y][1] = true; q.push(node(Point(x + 1, y, 1), u.dis + 1)); } //l if(check(x,y-1) && !vis[x][y-1][0] && mp[x][y-1] != 'E') { vis[x][y-1][0] = true; q.push(node(Point(x, y-1, 0), u.dis + 1)); } //r if(check(x, y+2) && !vis[x][y+2][0] && mp[x][y+2] != 'E') { vis[x][y+2][0] = true; q.push(node(Point(x, y + 2, 0), u.dis + 1)); } } else { //u if(check(x-1, y) && !vis[x-1][y][0] && mp[x-1][y] != 'E') { vis[x-1][y][0] = true; q.push(node(Point(x-1, y, 0), u.dis + 1)); } //d if(check(x + 2, y) && !vis[x + 2][y][0] && mp[x+2][y] != 'E') { vis[x + 2][y][0] = true; q.push(node(Point(x+2, y, 0), u.dis + 1)); } //l if(check(x, y - 1) && check(x + 1, y - 1) && !vis[x][y - 1][2]) { vis[x][y - 1][2] = true; q.push(node(Point(x, y - 1, 2), u.dis + 1)); } //r if(check(x, y + 1) && check(x + 1, y + 1) && !vis[x][y + 1][2]) { vis[x][y+1][2] = true; q.push(node(Point(x, y + 1, 2), u.dis + 1)); } } } return -1; } int main() { Read(); int i, j; while(~scanf("%d%d", &R, &C)) { if(R + C == 0) break; s1 = Point(-1, -1, -1); s2 = Point(-1, -1, -1); for(i = 0; i < R; ++i) { scanf("%s", mp[i]); for(j = 0; j < C; ++j) { if(mp[i][j] == 'X') { if(s1.x == -1) s1 = Point(i, j, -1); else s2 = Point(i, j, -1); } if(mp[i][j] == 'O') { tg = Point(i, j, 0); } } } if(s2.x != -1) { if(s1.x == s2.x) { s1.y = min(s1.y, s2.y); s1.f = 1; } else { s1.x = min(s1.x, s2.x); s1.f = 2; } } else { s1.f = 0; } int ans = bfs(); if(ans == -1) puts("Impossible"); else printf("%d\n", ans); } return 0; }
广搜的状态优化
POJ 1184
这题过的好揪心,这两天忙着复习,3天才过掉。。。
开始直接暴力bfs,然后果断MLE掉,优化一下内存有TLE掉 。后来看题解,有这个ppthttp://wenku.baidu.com/view/0c2742fb770bf78a65295406.html
还有这个解题报告:http://hi.baidu.com/kmzchchycfdeovr/item/6d7358b32be4edf762388eb6
注意,这个解题报告是错误的,不能忽略左移的情况。不如这个数据:000159 000519
思路是对于移动操作和数值变换操作分开处理。
先预处理出移动操作到达某个状态时用到的最小次数。至于这个状态,因为有六个位置,所以可以设定为num[0...5]记录当前和六个位置顺序状态,num[6]记录这六个位置被访问过的状态,num[7]记录到达这个状态的最小步数。被访问过的位置的状态有:
int Psta[10][6] = { {1, 0, 0, 0, 0, 0},//0 {1, 1, 0, 0, 0, 0},//1 {1, 1, 1, 0, 0, 0},//2 {1, 1, 1, 1, 0, 0},//3 {1, 1, 1, 1, 1, 0},//4 {1, 0, 0, 0, 0, 1},//5 {1, 1, 0, 0, 0, 1},//6 {1, 1, 1, 0, 0, 1},//7 {1, 1, 1, 1, 0, 1},//8 {1, 1, 1, 1, 1, 1} //9 };
bfs时记录当前六个位置的顺序状态,当前光标的位置,当前被访问过的位置状态(Psta),还有当前用掉的步数。
这个预处理出来每种六个位置顺序状态所用的步数。然后与目标数字进行对比,需要增加或者减少的直接累加上就可以。。。
ps:debug了好久,因为某傻冒错误。。。T_T
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("data.out", "w", stdout); typedef long long LL; const double eps = 1e-6; const double PI = acos(-1.0); const int inf = ~0u>>2; using namespace std; struct node { int a[6]; int pos, sta, stp; }; queue<node> q; int Psta[10][6] = { {1, 0, 0, 0, 0, 0},//0 {1, 1, 0, 0, 0, 0},//1 {1, 1, 1, 0, 0, 0},//2 {1, 1, 1, 1, 0, 0},//3 {1, 1, 1, 1, 1, 0},//4 {1, 0, 0, 0, 0, 1},//5 {1, 1, 0, 0, 0, 1},//6 {1, 1, 1, 0, 0, 1},//7 {1, 1, 1, 1, 0, 1},//8 {1, 1, 1, 1, 1, 1} //9 }; bool vis[10][6][6][6][6][6][6][6]; int num[50000][8], t; void bfs() { while(!q.empty()) q.pop(); CL(vis, false); CL(num, 0); t = 0; node u, v; int i; u.pos = 0; u.sta = 0; u.stp = 0; for(i = 0; i < 6; ++i) u.a[i] = i; q.push(u); vis[0][0][0][1][2][3][4][5] = true; while(!q.empty()) { u = q.front(); q.pop(); for(i = 0; i < 6; ++i) { num[t][i] = u.a[i]; } num[t][6] = u.sta; num[t++][7] = u.stp; v = u; ++v.stp; if(v.pos > 0) { swap(v.a[0], v.a[v.pos]); if(!vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]]) { vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]] = true; q.push(v); } swap(v.a[0], v.a[v.pos]); --v.pos; if(!vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]]) { vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]] = true; q.push(v); } ++v.pos; } if(v.pos < 5) { ++v.pos; if(v.pos > v.sta || (v.sta > 4 && v.pos > v.sta - 5)) { if(v.sta == 4 || v.sta == 9) v.sta = 9; else ++v.sta; } if(!vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]]) { vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]] = true; q.push(v); } v = u; ++v.stp; swap(v.a[5], v.a[v.pos]); if(v.sta <= 4) v.sta += 5; if(!vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]]) { vis[v.sta][v.pos][v.a[0]][v.a[1]][v.a[2]][v.a[3]][v.a[4]][v.a[5]] = true; q.push(v); } } } } int a[6], b[6]; int main() { //freopen("data.in", "r", stdin); //freopen("data1.out", "w", stdout); bfs(); int st, ed, i, j; while(~scanf("%d%d", &st, &ed)) { for(i = 5; i >= 0; --i) { a[i] = st%10; st /= 10; } for(i = 5; i >= 0; --i) { b[i] = ed%10; ed /= 10; } int ans = inf, stp, p; for(i = 0; i < t; ++i) { stp = num[i][7]; /*if(num[i][6] == 9) { for(j = 0; j < 6; ++j) { printf("%d", num[i][j]); } printf(" %d %d\n", num[i][6], num[i][7]); }*/ /* for(j = 0; j < 6; ++j) { printf("%d", num[i][j]); } printf(" %d %d\n", num[i][6], num[i][7]); */ for(j = 0; j < 6; ++j) { if(a[num[i][j]] != b[j] && !Psta[num[i][6]][j]) break; else stp += abs(a[num[i][j]] - b[j]); } if(j == 6 && stp < ans) {ans = stp; p = i;} } /* puts("**************"); for(j = 0; j < 6; ++j) printf("%d", a[num[p][j]]); puts("\n***************"); */ printf("%d\n", ans); } return 0; }
POJ 1324
话说做完这题真想写个贪吃蛇游戏。
因为蛇的身子很小,只有八个坐标,可以只记录蛇头的位置,然后记录每一个与前一个位置的相对位置关系。只有上下左右,用0, 1, 2, 3表示,这样就可以化成4进制的状态压缩了。直接bfs,注意蛇头走的下一个位置不能碰到蛇身上
时间耗时很大, 写的很烂。。。不知道用A*怎么写。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> //#include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("data.out", "w", stdout); typedef long long LL; const double eps = 1e-8; const double PI = acos(-1.0); const int inf = ~0u>>2; using namespace std; struct snake { int x, y; int sta; int dis; snake() {} snake(int a, int b, int c, int d) : x(a), y(b), sta(c), dis(d) {} }; snake st; queue<snake> q; bool vis[21][21][16390]; bool mp[21][21]; int n, m, l; int body[9][2]; int ssta[9]; int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1},}; void get_ssta(int sta) { for(int i = 0; i < l-1; ++i) { ssta[i] = sta%4; sta /= 4; } } void get_body(snake u) { body[l-1][0] = u.x; body[l-1][1] = u.y; get_ssta(u.sta); for(int i = l - 2; i >= 0; --i) { body[i][0] = body[i+1][0] + dir[ssta[i]][0]; body[i][1] = body[i+1][1] + dir[ssta[i]][1]; } } bool inmap(int x, int y) { if(x <= 0 || x > n || y <= 0 || y > m) return false; return true; } bool check(int x, int y) { if(mp[x][y] == true || !inmap(x, y)) return false; for(int i = 0; i < l; ++i) { if(x == body[i][0] && y == body[i][1]) return false; } return true; } int pos(int a, int b, int x, int y) { x -= a; y -= b; for(int i = 0; i < 4; ++i) { if(x == dir[i][0] && y == dir[i][1]) return i; } return -1; } int bfs() { while(!q.empty()) q.pop(); q.push(st); snake u; CL(vis, false); vis[st.x][st.y][st.sta] = true; int x, y, i, j, nsta, a, b; while(!q.empty()) { u = q.front(); q.pop(); if(u.x == 1 && u.y == 1) return u.dis; get_body(u); for(j = 0; j < 4; ++j) { x = u.x + dir[j][0]; y = u.y + dir[j][1]; if(!check(x, y)) continue; nsta = 0; a = x; b = y; for(i = l - 1; i >= 1; --i) { nsta = nsta*4 + pos(a, b, body[i][0], body[i][1]); a = body[i][0]; b = body[i][1]; } if(!vis[x][y][nsta]) { vis[x][y][nsta] = true; q.push(snake(x, y, nsta, u.dis + 1)); } } } return -1; } int main() { //Read(); int i, k, a, b, x, y, cas = 0; while(~scanf("%d%d%d", &n, &m, &l)) { if(n + m + l == 0) break; CL(vis, false); scanf("%d%d", &a, &b); st.x = a; st.y = b; st.sta = st.dis = 0; for(i = 1; i < l; ++i) { scanf("%d%d", &x, &y); st.sta = st.sta*4 + pos(a, b, x, y); a = x; b = y; } scanf("%d", &k); CL(mp, false); while(k--) { scanf("%d%d", &a, &b); mp[a][b] = true; } printf("Case %d: %d\n", ++cas, bfs()); } return 0; }