POJ 搜索(3)
|
搜索 |
较麻烦的搜索题目训练 |
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。
View Code
//#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
View Code
//#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*怎么写。。。
View Code
//#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; }

View Code
浙公网安备 33010602011771号