BZOJ 2464 小明的游戏

来源:互联网 发布:php取数组中的最大值 编辑:程序博客网 时间:2024/05/22 00:44

2464: 中山市选[2009]小明的游戏

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 829  Solved: 338
[Submit][Status][Discuss]

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

Sample Output

2
0

HINT

对于100%的数据满足:1 < = n, m <= 500


一道最短路的模板题,瓶颈在于如何将二维节点建图,所以采取给节点编号的方式,每一个点[i,j]的编号对应为(i-1)*n+j.


#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<cstdlib>#define INF 1000000000using namespace std;const int MAXN=1010;const int MAXQ=255000;struct edge{int next,to,val;};edge e[MAXN*MAXN*4];int head[MAXN*MAXN],cnt;char a[MAXN][MAXN];const int dx[4]={-1,0,1,0};const int dy[4]={0,1,0,-1};void addedge(int u,int v,int w){e[++cnt].next=head[u];e[cnt].to=v;e[cnt].val=w;head[u]=cnt;}bool inqueue[MAXN*MAXN];int dis[MAXN*MAXN];int n,m;int q[MAXQ];void spfa(int s){for (int i=1;i<=n*m;i++){dis[i]=INF;}int l=0,r=1;q[1]=s;inqueue[s]=1;dis[s]=0; while (l!=r){l++;if (l==MAXQ){l=0;}int x=q[l];for (int i=head[x];i;i=e[i].next){if (dis[x]+e[i].val<dis[e[i].to]){dis[e[i].to]=dis[x]+e[i].val;if (!inqueue[e[i].to]){r++;if (r==MAXQ){r=0;}q[r]=e[i].to;inqueue[e[i].to]=1;}}}inqueue[x]=0;}}int main(){scanf("%d%d",&n,&m);while (n!=0 || m!=0){memset(head,0,sizeof(head));cnt=0;for (int i=1;i<=n;i++){char c[510];scanf("%s",c+1);for (int j=1;j<=m;j++){a[i][j]=c[j];}}for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){char b=a[i][j];for (int k=0;k<4;k++){int nx=i+dx[k],ny=j+dy[k];if (nx>n || ny>m || nx<=0 || ny<=0){continue;}int pos=(i-1)*m+j;pos+=dx[k]*m;pos+=dy[k];if (a[nx][ny]==b){addedge((i-1)*m+j,pos,0);}else{addedge((i-1)*m+j,pos,1);}}}}int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);spfa((x1)*m+y1+1);printf("%d\n",dis[(x2)*m+y2+1]);   scanf("%d%d",&n,&m);} return 0;}

一种优化:提前开一个数组g[i,j],记录每一个点对应的坐标,这样在读入时只需要开一个cnt变量,读进来一个数就cnt++,对应的一定是这个点的编号。