题干:
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 ;
}