454. 帮帮小叮当
时间限制 1500 ms
内存限制 65536 KB
题目描述
小叮当刚刚学会了传送门的使用方法,可是它不小心跌落到二维空间一个 n * m 的矩阵格子世界的入口(1,1)处,
他得知出口在(n,m)处,每穿越一个格子门,它的体力值会下降。
又饿又累的他 IQ 已经降为负数了,聪明的你,能帮他规划一下路线,使得它体力值下降的最少吗?
每一行有且仅有一个传送门,但是小叮当上课睡着了,只学会了用传送门瞬移到相邻行的另一个传送门且耗 1 滴体力。
此外,他就只能通过格子门走到相邻四个格子中的一个,也耗 1 滴体力。
ps,由于符合的路径太多了,你只需要告诉我们体力值消耗最小值。
输入格式
每组数据,第一行给 n,m 两个整数(2 <= n,m <= 10000),接下来一行,有 n 个数字,代表该行传送门的位置 x( 1 <= x <= m )。以 n,m 都为0结束。Mays温馨提醒:数据组数略大于100。
输出格式
对每组输入,输出一行,体力消耗最小值。
输入样例
5 5
5 4 3 2 1
0 0
输出样例
8
思路:其实,对于一开始的格子,最少走n*m步就可以到达了。然后其实你只要枚举你每次要不要直接走到终点或者到达下一个口,则就是(1,1)向各个传送门建一条权值位曼哈顿距离的边,以及终点建一个曼哈顿距离的边,对于每个传送门都建一条曼哈顿距离的到终点的边和到下一个传送门的权值为1的边。再一边SPFA即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#define M 20000
#define maxn 20005
//#define LOCAL
using namespace std;
struct Point
{
int x,y;
}door[maxn];
struct Edge
{
int from,to,next,v;
}e[4*maxn];
int n,m,cnt;
int h[maxn],q[2*maxn],vis[maxn],dist[maxn];
int getdis(int i,int j)
{
return fabs(door[i].x-door[j].x)+fabs(door[i].y-door[j].y);
}
void Addedge(int x,int y,int v)
{
cnt++;e[cnt].from=x;e[cnt].to=y;e[cnt].v=v;e[cnt].next=h[x];h[x]=cnt;
}
void Init()
{
for(int i=1;i<=n+1;i++){Addedge(0,i,getdis(0,i));Addedge(i,0,getdis(0,i));}
for(int i=1;i<=n-1;i++)
{
Addedge(i,i+1,1);
Addedge(i,n+1,getdis(i,n+1));
Addedge(i+1,i,1);
Addedge(n,i,getdis(i,n+1));
}
Addedge(n,n+1,getdis(n,n+1));
Addedge(n+1,n,getdis(n,n+1));
}
void spfa()
{
for(int i=0;i<=n+1;i++)dist[i]=2000000000;
int S=0;
dist[S]=0;int head=0,tail=0;
q[++tail]=S;vis[S]=1;
while(head<tail)
{
head++;
int u=q[head];
for(int i=h[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dist[u]+e[i].v<dist[v])
{
dist[v]=dist[u]+e[i].v;
if(!vis[v])
{
vis[v]=1;tail++;q[tail]=v;
}
}
}
vis[u]=0;
}
}
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
#endif // LOCAL
while(scanf("%d%d",&n,&m)==2,n&&m)
{
cnt=0;
memset(h,-1,sizeof(h));
memset(vis,0,sizeof(vis));
door[0].x=1;door[0].y=1;
for(int i=1;i<=n;i++){door[i].x=i;scanf("%d",&door[i].y);}
door[n+1].x=n;door[n+1].y=m;
Init();
spfa();
printf("%d\n",dist[n+1]);
}
return 0;
}