题干:
n*m矩阵a.若a[i][j]==1则可以往左右走,若a[i][j]==0 则可以往上下走.
每一秒可以按上述规则移动,并且每秒钟矩阵所有的值翻转。
n*m<=1e5.问从(sx,sy)到(tx,ty)的最短时间.
解题报告:
这题因为不带权值所以不需要考虑Dijkstra,可以根据时间直接判断状态是0还是1。如果状态的变换很复杂的话就考虑分层图就好了。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
const int MAX = 3e5 + 5;
int n,m;
bool vis[MAX][2];
int nx[4] = {-1,1,0,0};//上,下,左,右
int ny[4] = {0,0,-1,1};
int sta[MAX];
struct Node {
int x,y;
int pos,t;
Node(){}
Node(int x,int y,int pos,int t):x(x),y(y),pos(pos),t(t){}
};
inline int getp(int x,int y) {
return (x-1) * m + y;
}
int bfs(int a,int b,int c,int d,int st,int ed) {
queue<Node > q;
q.push(Node(a,b,st,0));
vis[st][sta[st]]=1;
while(!q.empty()) {
Node cur = q.front();q.pop();
if(cur.pos == ed) return cur.t;
int nowsta = (cur.t%2==0) ? sta[cur.pos] : 1-sta[cur.pos];
if(nowsta == 0) {
for(int k = 0; k<2; k++) {
int tx = cur.x + nx[k];
int ty = cur.y + ny[k];
if(tx <1 || tx >n || ty < 1 || ty > m) continue;
if(vis[getp(tx,ty)][nowsta]) continue;
vis[getp(tx,ty)][nowsta] = 1 ;
q.push(Node(tx,ty,getp(tx,ty),cur.t+1));
}
}
else {
for(int k = 2; k<4; k++) {
int tx = cur.x + nx[k];
int ty = cur.y + ny[k];
if(tx <1 || tx >n || ty < 1 || ty > m) continue;
if(vis[getp(tx,ty)][nowsta]) continue;
vis[getp(tx,ty)][nowsta] = 1 ;
q.push(Node(tx,ty,getp(tx,ty),cur.t+1));
}
}
}
return -1;
}
int main()
{
int t;
cin>>t;
while(t--) {
scanf("%d%d",&n,&m);
for(int i = 1; i<=n; i++) {
for(int j = 1; j<=m; j++) {
vis[(i-1)*m+j][0]=0;
vis[(i-1)*m+j][1]=0;
}
}
for(int i = 1; i<=n; i++) {
for(int j = 1; j<=m; j++) {
scanf("%d",&sta[(i-1)*m + j]);
}
}
int stx,sty,edx,edy,st,ed;
scanf("%d%d",&stx,&sty);
scanf("%d%d",&edx,&edy);
st = (stx-1) * m + sty;
ed = (edx-1) * m + edy;
int ans = bfs(stx,sty,edx,edy,st,ed);
printf("%d\n",ans);
}
return 0 ;
}