POJ 1324 Holedox Moving 搜索
题目地址: http://poj.org/problem?id=1324
优先队列---A*的估价函数不能为蛇头到(1,1)的距离,这样会出错。
看了discuss,有大神说这题A*的估价函数为BFS (0,0)到各点的花费在乘上10 ,但是还是不清楚,希望知道的可以给我留个言,谢谢了。
思路:
用0,1,2,3表示方向,这样就可以用四进制状态压缩了。
总共需要3+3*4^1+……3*4^6.
推荐大家能不用STL就不用STL,太浪费时间了。
下面是用STL超时代码和用数组模拟AC代码。
超时代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <vector> #include <list> #include <deque> #include <queue> #include <iterator> #include <stack> #include <map> #include <set> #include <algorithm> #include <cctype> using namespace std; typedef long long LL; const int N=21; const LL II=1000000007; int n,m,L; int maps[N][N];//0代表空,1代表蛇身体,2代表石头 bool vis[N][N][17000];//状态压缩 int t[4][2]={0,-1,1,0,0,1,-1,0}; struct xh { int step; int po[11][2]; }w,e; int location(int px,int py,int nx,int ny)//求两个节点的相对位置 { if(px==nx) { if(py>ny) return 0; else return 1; } else { if(px>nx) return 2; else return 3; } } int gethash(int B[][2]) {//得到状态 int s=0; for(int i=0;i<L-1;i++) s=s*4+location(B[i][0],B[i][1],B[i+1][0],B[i+1][1]); return s; } bool inmap(int x,int y,xh a) { if(!(x>=1&&x<=n&&y>=1&&y<=m)) return false; if(maps[x][y]==2) return false; for(int i=0;i<L;i++)//蛇头和蛇尾相连也不行的 if(x==a.po[i][0]&&y==a.po[i][1])//判断是否这一步为蛇身 return false; return true; } void bfs() { int i,j,hash,x,y; w.step=0; hash=gethash(w.po); x=w.po[0][0]; y=w.po[0][1]; vis[x][y][hash]=true; queue<xh> q; q.push(w); if(x==1&&y==1) { printf("0\n"); return ; } while(!q.empty()) { e=q.front(); q.pop(); for(i=0;i<4;i++) { w=e; x=w.po[0][0]; y=w.po[0][1]; x+=t[i][0]; y+=t[i][1]; if(!inmap(x,y,w)) continue; for(j=L-1;j>=1;j--) { w.po[j][0]=w.po[j-1][0]; w.po[j][1]=w.po[j-1][1]; } w.po[0][0]=x; w.po[0][1]=y; hash=gethash(w.po); if(vis[x][y][hash]) continue; vis[x][y][hash]=true; w.step++; q.push(w); if(x==1&&y==1) { printf("%d\n",w.step); return ; } } } printf("-1\n"); } int main() { int i,k,ci=0; while(scanf("%d%d%d",&n,&m,&L)&&(n+m+L)) { memset(maps,0,sizeof(maps)); memset(vis,false,sizeof(vis)); for(i=0;i<L;i++) { scanf("%d%d",&w.po[i][0],&w.po[i][1]); } scanf("%d",&k); while(k--) { int a,b; scanf("%d%d",&a,&b); maps[a][b]=2;//石头 } printf("Case %d: ",++ci); bfs(); } return 0; }
用STL写就超时了,用数组模拟就过了
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <vector> #include <list> #include <deque> #include <queue> #include <iterator> #include <stack> #include <map> #include <set> #include <algorithm> #include <cctype> using namespace std; typedef long long LL; const int N=21; const LL II=1000000007; int n,m,L; int maps[N][N];//0代表空,1代表蛇身体,2代表石头 bool vis[N][N][17000];//状态压缩 int t[4][2]={0,-1,1,0,0,1,-1,0}; struct xh { int step; int po[11][2]; }w,e,q[5000004]; int location(int px,int py,int nx,int ny)//求两个节点的相对位置 { if(px==nx) { if(py>ny) return 0; else return 1; } else { if(px>nx) return 2; else return 3; } } int gethash(int B[][2]) {//得到状态 int s=0; for(int i=0;i<L-1;i++) s=s*4+location(B[i][0],B[i][1],B[i+1][0],B[i+1][1]); return s; } bool inmap(int x,int y,xh a) { if(!(x>=1&&x<=n&&y>=1&&y<=m)) return false; if(maps[x][y]==2) return false; for(int i=0;i<L;i++)//蛇头和蛇尾相连也不行的 if(x==a.po[i][0]&&y==a.po[i][1])//判断是否这一步为蛇身 return false; return true; } void bfs() { int i,j,hash,x,y,head=0,tail=0; w.step=0; hash=gethash(w.po); x=w.po[0][0]; y=w.po[0][1]; vis[x][y][hash]=true; q[tail++]=w; if(x==1&&y==1) { printf("0\n"); return ; } while(head<tail) { e=q[head++]; for(i=0;i<4;i++) { w=e; x=w.po[0][0]; y=w.po[0][1]; x+=t[i][0]; y+=t[i][1]; if(!inmap(x,y,w)) continue; for(j=L-1;j>=1;j--) { w.po[j][0]=w.po[j-1][0]; w.po[j][1]=w.po[j-1][1]; } w.po[0][0]=x; w.po[0][1]=y; hash=gethash(w.po); if(vis[x][y][hash]) continue; vis[x][y][hash]=true; w.step++; q[tail++]=w; if(x==1&&y==1) { printf("%d\n",w.step); return ; } } } printf("-1\n"); } int main() { int i,k,ci=0; while(scanf("%d%d%d",&n,&m,&L)&&(n+m+L)) { memset(maps,0,sizeof(maps)); memset(vis,false,sizeof(vis)); for(i=0;i<L;i++) { scanf("%d%d",&w.po[i][0],&w.po[i][1]); } scanf("%d",&k); while(k--) { int a,b; scanf("%d%d",&a,&b); maps[a][b]=2;//石头 } printf("Case %d: ",++ci); bfs(); } return 0; }