题目描述 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;
}