4 4 SX.. XX.. .... 1..D 4 4 S.X1 .... ..XX ..XD 0 0
-1 9
题意:要求从 S 点走到 D 点的最短时间,‘1’~‘9’:表示当前位置有炸药数量,X:表示墙。" . ":表示可走的路。墙可以用一包炸药炸通,需花一个单位时间。
分析:从S到D,所经过的每个位置得到的炸药数量可能不等,就算得到的炸药数量相等,但每个到达当前位置时的地图的状态不同。所以我们不仅必须判断在每个位置得到的炸药数是否存在过,而且还要判断得到的这些炸药数在相同情况下不同地图的状态。
#include<stdio.h> #include<iostream> #include<queue> #include<vector> #include<string.h> using namespace std; struct State { short state[8];//地图每行压缩的状态, }; struct node { int x,y; //当前走到的位置 int time,explosiveNumb; //走过的时间,得到的炸药数量 State s; //走过后的地图状态 friend bool operator<(const node &a,const node &b) //优先队列以时间最小的顺序取 { return a.time>b.time; } }; int n,m; char map[10][10]; vector<State>vist[8][8][560]; //走到地图每个位置得到不同炸药数量的地图状态有没有存在过 void init() { for(int i=0; i<n; i++) for(int j=0; j<m; j++) for(int k=0; k<559; k++) vist[i][j][k].clear(); } bool judge(int x,int y,int numb,short state[]) { int length=vist[x][y][numb].size(); for(int i = 0; i < length ;i++) { int j; for(j = 0; j<n ; j++) if(vist[x][y][numb][i].state[j]!=state[j]) break; if(j==n) //当前将要走的state[]地图状态,不必再加入队列(即己经存在过) return false; } //当前将要走的地图状态没存在过,需加入队列 return true; } int bfs(int sx,int sy) { int dir[4][2]={0,1,0,-1,1,0,-1,0}; priority_queue<node>q; node p,tp; init(); p.x=sx; p.y=sy; p.time=0; p.explosiveNumb=0; for(int i=0;i<n;i++) { p.s.state[i]=0; //压缩每行地图的状态,位置是 1 表示不存在任何东西 for(int j=0;j<m;j++) if(map[i][j]=='.') p.s.state[i]|=(1<<j); } vist[sx][sy][0].push_back(p.s); q.push(p); while(!q.empty()) { p=q.top(); q.pop(); for(int e=0;e<4;e++) { tp=p; tp.x+=dir[e][0]; tp.y+=dir[e][1]; tp.time++; if(tp.x>=0&&tp.x<n&&tp.y>=0&&tp.y<m) { if(!(tp.s.state[tp.x]&(1<<tp.y))&&map[tp.x][tp.y]=='X'&&!tp.explosiveNumb) //表示将要走的位置是现在还没炸的墙,并且身上没有炸药 continue ; if(!(tp.s.state[tp.x]&(1<<tp.y))&&map[tp.x][tp.y]>'0'&&map[tp.x][tp.y]<='9') //表示将要走的位置是没有取走的炸药 { tp.explosiveNumb+=map[tp.x][tp.y]-'0'; tp.s.state[tp.x]|=1<<tp.y; //取走后变成 "." } else if(!(tp.s.state[tp.x]&(1<<tp.y))&&map[tp.x][tp.y]=='X'&&tp.explosiveNumb) //表示将要走的位置是现在还没炸的墙,身上有炸药 { tp.explosiveNumb--; tp.s.state[tp.x]|=1<<tp.y; //炸完后变成 "." tp.time++; } else if(map[tp.x][tp.y]=='D') return tp.time; if(judge(tp.x,tp.y,tp.explosiveNumb,tp.s.state)) //判断走到当前位置的炸药数量与地图状态是否没有存在过?为真没存在过,否则为存在过 vist[tp.x][tp.y][tp.explosiveNumb].push_back(tp.s),q.push(tp); } } } return -1; } int main() { int sx,sy; while(scanf("%d%d",&n,&m)>0) { if(n==0&&m==0) break; for(int i=0;i<n;i++) scanf("%s",map[i]); for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(map[i][j]=='S') sx=i,sy=j; printf("%d\n",bfs(sx,sy)); } }
HDU2128Tempter of the Bone II(bfs+状态压缩)
原文地址:http://blog.csdn.net/u010372095/article/details/41595083