tzl155 @ 2025-01-11 15:29:43
rt.题目:
问题 E: HJ1-T5魔塔救公主
内存限制:128 MB 时间限制:1.000 S
评测方式:普通裁判 命题人:chengsong
题目描述
你正在玩一款魔塔游戏,你要在规定的地图中救出公主。现在你来到了新的一关(数字组成的二维数组),必须要从上到下通过此数组才算过关。这一关用不同的数字表示不同颜色的地板,连在一起(水平或竖直相邻才算连在一起)的地板可以不消耗体力一次性通过。也就是你通过的路线上切换一次数字,消耗的体力就要加1。为了给其他关卡节约体力,你需要计算通过本关消耗的最少体力。
比如地图如下:
1 1 2 2 3 4
1 2 3 2 5 4
3 4 5 6 7 4
1 4 5 8 7 4
2 5 5 7 7 1
你可以从第六列的4地板消耗1体力走到第4行,再消耗1体力走第六列的1地板通关,消耗体力的总数为2。
输入
第一行两个整数,n和m表示地图的行列数(0<n,m<21);
下面n行,每行m个数,用空格隔开,数组中每个元素取值为0-9。
输出
一个整数,表示你通过这关需要的最少体力数。
样例输入
5 6
1 1 2 2 3 4
1 2 3 2 5 4
3 4 5 6 7 4
1 4 5 8 7 4
2 5 5 7 7 1
样例输出
2
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,c,tot,to[1000010],nxt[1000010],head[1000010],val[1000010];
int mapnum,mapf[500];
void add(int x,int y,int z)
{
to[++tot]=y;
nxt[tot]=head[x];
val[tot]= z;
head[x]=tot;
}
int spfa(int start)
{
int f[500],v[500];
memset(f,0x3f,sizeof(f));
memset(v,0,sizeof(v));
queue<int> q;
q.push(start),f[start]=0,v[start]=1;
while(q.size())
{
int x,y;
x=q.front();
q.pop();
v[x]=0;
for(int i=head[x];i;i=nxt[i])
if(f[y=to[i]]>f[x]+val[i])
{
f[y]=f[x]+val[i];
if(v[y]==0) q.push(y),v[y]=1;
}
}
int ans=0x3f3f3f3f;
for(int i=1;i<=m;i++)
{
ans=min(ans,f[(n-1)*m+i]);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
mapnum=n*m;
for(int i=1;i<=mapnum;i++)
scanf("%d",&mapf[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(i==1)add(0,j,1);
else add((i-1)*m+j,(i-1)*m+j-m,(int)mapf[(i-1)*m+j]!=mapf[(i-1)*m+j-m]),add((i-1)*m+j-m,(i-1)*m+j,(int)mapf[(i-1)*m+j]!=mapf[(i-1)*m+j-m]);
if(j!=1)add((i-1)*m+j,(i-1)*m+j-1,(int)(mapf[(i-1)*m+j]!=mapf[(i-1)*m+j-m])),add((i-1)*m+j-1,(i-1)*m+j,(int)(mapf[(i-1)*m+j]!=mapf[(i-1)*m+j-m]));
}
printf("%d",spfa(0));
}