每个点向它旁边的点连边,相同dis为0,不同为1。
n=3,m=3每个点的标号如下:
1 2 3
4 5 6
7 8 9
这样安排标号唯一,标号计算公式$(i-1)* m+j$,连边时判断一下边界,因为题目默认坐标是从(0,0)开始,所以方便做题,将读入的起点和终点坐标都加1。然后跑个最短路就可以了
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; int n,m; int ex,ey,px,py; int a[505][505]; char ch[255]; struct node{ int to,nxt,dis; }e[20000005]; int head[250005],cnt,dis[250005],in[250005]; inline void add(int from,int to,int dis){ e[++cnt]=(node){to,head[from],dis}; head[from]=cnt; } void spfa(){ queue<int>q; for(int i=1;i<=n*m;++i) dis[i]=2000000000,in[i]=0; dis[(ex-1)*m+ey]=0; in[(ex-1)*m+ey]=1; q.push((ex-1)*m+ey); while(!q.empty()){ int now=q.front(); q.pop(); in[now]=0; for(int i=head[now];i;i=e[i].nxt) if(dis[now]+e[i].dis<dis[e[i].to]){ dis[e[i].to]=dis[now]+e[i].dis; if(!in[e[i].to]){ q.push(e[i].to); in[e[i].to]=1; } } } printf("%d ",dis[(px-1)*m+py]); } int main(){ while(scanf("%d%d",&n,&m)){ if(n==0&&m==0)break; cnt=0; memset(head,0,sizeof(head)); for(int i=1;i<=n;++i){ scanf("%s",ch+1); for(int j=1;j<=m;++j){ if(ch[j]=='@')a[i][j]=1; else a[i][j]=0; } } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ if(i>1) add((i-1)*m+j,(i-2)*m+j,a[i][j]^a[i-1][j]),add((i-2)*m+j,(i-1)*m+j,a[i][j]^a[i-1][j]); if(i<n) add((i-1)*m+j,i*m+j,a[i][j]^a[i+1][j]),add(i*m+j,(i-1)*m+j,a[i][j]^a[i+1][j]); if(j>1) add((i-1)*m+j,(i-1)*m+j-1,a[i][j]^a[i][j-1]),add((i-1)*m+j-1,(i-1)*m+j,a[i][j]^a[i][j-1]); if(j<m) add((i-1)*m+j,(i-1)*m+j+1,a[i][j]^a[i][j+1]),add((i-1)*m+j+1,(i-1)*m+j,a[i][j]^a[i][j+1]); } scanf("%d%d%d%d",&ex,&ey,&px,&py); ex++;ey++;px++;py++; spfa(); } return 0; }