20190801 bfs双向搜索 | Knight Moves
loj#10028. 「一本通 1.4 例 3」Knight Moves
用双向宽度搜索,可以节省许多计算次数
/* 刚开始看这道题还以为是骑士精神呢 仔细看题后,发现它应该比骑士精神简单一些 骑士精神是是一整张棋盘达到目标棋盘状态(使用bfs太慢,于是用迭代加深+可行性剪枝dfs) 而本题是让一个棋子达到目标位置 (bfs可以,再加上双向搜索会减少很多延伸出去的可行解,减少了计算量,加快了速度) */ #include<cstdio> #include<queue> #include<cstring> using namespace std; int l; int ax[9] = {0,1,1,-1,-1,2,2,-2,-2}; int ay[9] = {0,2,-2,2,-2,1,-1,1,-1}; int dis[2][305][305],v[2][305][305]; struct node { int x,y; }; queue<node>q[2]; int ans; int safe(int x,int y) { if(x >= 1 && x <= l && y >= 1 && y <= l)return 1; else return 0; } int expand(int k) { node mid = q[k].front(); q[k].pop(); int x = mid.x; int y = mid.y; int d = dis[k][x][y]; for(int i = 1;i <= 8;i ++) { node t; t.x = x + ax[i],t.y = y + ay[i]; if(safe(t.x,t.y) && !v[k][t.x][t.y]) { v[k][t.x][t.y] = 1; dis[k][t.x][t.y] = d + 1; if(v[1 - k][t.x][t.y]) { ans = dis[k][t.x][t.y] + dis[1 - k][t.x][t.y]; return 1; } q[k].push(t); } } return 0; } void bfs() { ans = 0; while(!q[0].empty() && !q[1].empty()) { if(q[0].size() <= q[1].size()) { if(expand(0))return; } else { if(expand(1))return; } } } int main() { int n; scanf("%d",&n); while(n --) { memset(v,0,sizeof(v)); memset(dis,0,sizeof(dis)); while(!q[0].empty())q[0].pop(); while(!q[1].empty())q[1].pop(); node s,g; scanf("%d%d%d%d%d",&l,&s.x,&s.y,&g.x,&g.y); if(s.x == g.x && s.y == g.y) { printf("0\n"); } else { v[0][s.x][s.y] = 1; v[1][g.x][g.y] = 1; q[0].push(s); q[1].push(g); bfs(); printf("%d\n",ans); } } }