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

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。

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值