Description
小明最近喜欢玩一个游戏。给定一个n * m的棋盘,上面有两种格子#和@。游戏的规则很简单:给定一个起始位置和一个目标位置,小明每一步能向上,下,左,右四个方向移动一格。如果移动到同一类型的格子,则费用是0,否则费用是1。请编程计算从起始位置移动到目标位置的最小花费。
Input
输入文件有多组数据。
输入第一行包含两个整数n,m,分别表示棋盘的行数和列数。
输入接下来的n行,每一行有m个格子(使用#或者@表示)。
输入接下来一行有四个整数x1, y1, x2, y2,分别为起始位置和目标位置。
当输入n,m均为0时,表示输入结束。
Output
对于每组数据,输出从起始位置到目标位置的最小花费。每一组数据独占一行。
Sample Input
2 2
@#
#@
0 0 1 1
2 2
@@
@#
0 1 1 0
0 0
@#
#@
0 0 1 1
2 2
@@
@#
0 1 1 0
0 0
Sample Output
2
0
0
HINT
对于100%的数据满足:1 < = n, m <= 500。
Source
比较简单的题目……相邻的位置连边就好了。
当然这样的话先把二维点转化到一维,然后连完边,
再接下来……就是最短路了。。。
不想写dij+heap
结果SPFA的队列长度爆了几次……
气死了!
直接开循环队列!
好吧,转化到一维的报应就是时间比较慢……
400多ms啦
#include<bits/stdc++.h>
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int
N=505,
M=300005;
int n,m,Ecnt;
int dis[N*N],Q[M];
bool vis[N*N];
char s[N][N];
struct Edge{
int next,to,val;
}E[N*N<<1]; int head[N*N];
int vertex(int i,int j){
return (i-1)*m+j;
}
void add(int u,int v,int w){
E[++Ecnt].next=head[u];
E[Ecnt].to=v;
E[Ecnt].val=w;
head[u]=Ecnt;
E[++Ecnt].next=head[v];
E[Ecnt].to=u;
E[Ecnt].val=w;
head[v]=Ecnt;
}
void build(){
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
if (i-1) add(vertex(i,j),vertex(i-1,j),s[i][j]!=s[i-1][j]);
if (j-1) add(vertex(i,j),vertex(i,j-1),s[i][j]!=s[i][j-1]);
}
}
int SPFA(int sta,int end){
memset(vis,0,sizeof(vis));
memset(dis,60,sizeof(dis));
int h=0,tail=1;
Q[0]=sta; dis[sta]=0;
while (h!=tail){
int u=Q[h];
h=(h+1)%M;
vis[u]=0;
for (int i=head[u];i;i=E[i].next)
if (dis[u]+E[i].val<dis[E[i].to]){
dis[E[i].to]=dis[u]+E[i].val;
if (!vis[E[i].to]){
vis[E[i].to]=1;
Q[tail]=E[i].to;
tail=(tail+1)%M;
}
}
}
return dis[end];
}
int main(){
int x0,y0,x1,y1;
while (1){
n=read(),m=read();
if (!n) break;
Ecnt=0;
memset(head,0,sizeof(head));
for (int i=1;i<=n;i++)
scanf("%s",s[i]+1);
build();
x0=read(),y0=read(),x1=read(),y1=read();
x0++,y0++,x1++,y1++;
printf("%d\n",SPFA(vertex(x0,y0),vertex(x1,y1)));
}
return 0;
}