个人排位赛07D kari454 帮帮小叮当 SPFA

时间限制 5000 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
最短路问题,建图姿势很重要。该题,起点到各传送门,各传送门到终点,各个传送门之间,建图。由于是稀疏图,用SPFA做。
注意:用vector时记得clear,不然会出错。(相当于数组初始化)。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
struct edge
{
    int to,cost;
};
vector <edge> g[10010];
queue <int> p;
bool inp[10010];
int a[10010],d[10010];
int main()
{
    int n,m,i,sz;
    edge q;
    while(scanf("%d %d",&n,&m)&&n&&m)
    {
        for(i=0;i<=n+1;i++)
            g[i].clear();
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            q.to=i;
            q.cost=a[i]+i-2;
            g[0].push_back(q);
            q.cost=m+n-a[i]-i;
            q.to=n+1;
            g[i].push_back(q);
        }
        for(i=1;i<n;i++)
        {
            q.to=i+1;
            q.cost=1;
            g[i].push_back(q);
            q.to=i;
            g[i+1].push_back(q);
        }
        memset(inp,0,sizeof(bool)*(n+2));
        for(i=0;i<=n+1;i++)
            d[i]=(i==0?0:20000);
        p.push(0);
        while(!p.empty())
        {
            int x=p.front();
            p.pop();
            inp[x]=false;
            for(i=0,sz=g[x].size();i<sz;i++)
            {
                if(d[g[x][i].to]>d[x]+g[x][i].cost)
                {
                    d[g[x][i].to]=d[x]+g[x][i].cost;
                    if(!inp[g[x][i].to])
                    {
                        inp[g[x][i].to]=true;
                        p.push(g[x][i].to);
                    }
                }
            }
        }
        printf("%d\n",d[n+1]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值