CODE[VS] 2292 图灵机游戏 SPFA求最短路

本文介绍了一种名为“图灵机游戏”的趣味挑战,玩家需通过最少的操作使机器头到达指定位置。文章详细解析了解题思路,利用最短路径算法,并通过示例代码展示了如何构建图模型并求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述 Description

Shadow最近知道了图灵机是什么(Shadow:就是一行格子和一个机器头移来移去的呗!),于是他突发奇想,创造了一个新游戏——“图灵机游戏”(Shadow:好听吧?)。

游戏规则如下:

在一条长长的纸上有N个格子,每个格子上都有一个数,第i格的数记为Ai,机器头刚开始在第1格。这个游戏有两个操作:

1.如果现在在第i格,则可以移动机器头到第Ai格;

2.把某个Ai减少或增加1。

然而,fotile96看了之后却不以为然。“嗯,你挑战一下用最少次数使机器头到达第N格吧,这样好玩些……”

现在,Shadow已经快Crazy了。于是,Shadow把脸转向了你……

输入描述 Input Description
第1行,1个整数N;
第2行,N个整数Ai。
输出描述 Output Description
1行,1个整数,为最少的操作次数。

样例输入 Sample Input
5
3 4 2 5 3
样例输出 Sample Output
3

数据范围及提示 Data Size & Hint
对于30%的数据,1≤N≤10;
对于60%的数据,1≤N≤1000;
对于100%的数据,1≤N≤100000,1≤Ai≤N。

样例解释

1.先将第1格的值加1
2.跳到第4格
3.跳到第5格,结束游戏

DP? 这样的游戏规则容易造成这样的错觉 但是数据要求10w QAQ
怎!么!D!P!啊!
嗯…… 其实 这是最短路2333
首先容易判断的是:有许多点之间存在联通的关系 因为机器头是可以瞬移的 而且都是单向边
那么问题来了:建图
从 i —> a[i] 分别建 ? 显然不可以 因为是10w * 10w

因为在一个点上可以修改它所能到的边 那么我们就可以改辣
比如 i 点原来指向 j 点 我们改变 j (可以+1也可以-1) 那么到达中间目标z 变化的次数就为 | j - z |次 在进行一次移动 步数就为 | j - z | + 1 次
也就是说从该点到它所能到的最优点之间边权就是 | j - z | + 1
同理 从每个中间点到达终点的边权为 | n - j | + 1
这样就可以建图跑最短路了

代码如下:

#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct Edge
{
    int ff,tt,next,dd;
}edge[1000010];
int tot,head[100010],dist[100010],n;
void build(int ff,int tt,int dd)
{
    edge[++tot].ff=ff;
    edge[tot].tt=tt;
    edge[tot].dd=dd;
    edge[tot].next=head[ff];
    head[ff]=tot;
}
queue<int>q;
bool vis[100010];
void spfa()
{
    q.push(1);
    vis[1]=1;
    dist[1]=0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=head[x];i;i=edge[i].next)
        {
            Edge e=edge[i];
            if(dist[e.tt]>dist[x]+e.dd)
            {
                dist[e.tt]=dist[x]+e.dd;
                if(!vis[e.tt])
                {
                    q.push(e.tt);
                    vis[e.tt]=1;
                }
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;i++)
        dist[i]=0x7ffffff;
    for(int i=1;i<=n;i++)
    {
        int a;
        scanf("%d",&a);
        for(int j=a-4;j<=a+4;j++)
        {
            build(i,j,abs(j-a)+1);
        }
        build(i,n,abs(n-a)+1);
    }
    spfa();
    cout<<dist[n];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值