• [图论][最短路]步行


    题目描述

    ftiasch又开发了一个奇怪的游戏,这个游戏是这样的:有N个格子排成一列,每个格子上有一个数字,第i个格子的数字记为Ai。这个游戏有2种操作:
    1.如果现在在第i个格子,则可以跳到第Ai个格子。
    2.把某个Ai增加或减少1。
    nm开始在第1个格子,他需要走到第N个格子才能通关。现在他已经头昏脑涨啦,需要你帮助他求出,从起点到终点最少需要多少次操作。

    输入

    第1行,1个整数N。第2行,N个整数Ai。

    输出

    第1行,1个整数,表示最少的操作次数。

    样例输入

    5
    3 4 2 5 3
    

    样例输出

    3
    

    提示

    •对于30%的数据,1≤N≤10。
    •对于60%的数据,1≤N≤1,000。
    •对于100%的数据,1≤N≤100,000,1≤Ai≤N。

    题目大意:很清楚了,就不解释了。

    思路:建立图模型(如下),会发现其实等价于求起点到终点的最短路(bfs或几种最短路算法)。

    (样例:3 4 2 5 3,起点1,终点5,答案3)

    (样例:3 3 3 3 3 ,起点1,终点5,答案3)

    如何建立此图模型:

    1.建立起i到Ai的单向边,权值为1,表明从i到Ai需要操作1步;

    2.建立起i与i-1(如果存在的话),i与i+1(如果存在的话)的双向边,权值也都为1;

    (比如说有a[2]=4,那么不光要建立2到4的单向边,也要建立4与3,4与5的双向边)

    这个要好好理解,根据题意,可以对任意Ai加或减1,并算做一步操作,于是可以理解为:虽然a[2]=4(也就是2可以跳到4),但对a[2]进行加减1操作后,就意味着2也可以到3或5,当然操作数数也要加上1,所以建立相邻数的双向边意思是相邻数其实可以互通(对应着加减1操作),比如有a[2]=4,a[4]=1的话,当2跳到4后,4可以跳到1,3或5,同理接着5(假如上一步跳到了5)可以跳到a[5],4或者6...,那么从2到6的过程可以看作是2->4->5->6(等价于把a[2]加1再加1变成6后跳到6)。

    可以自己再琢磨一下上面两个图。

    还有需要明白的是,对于所在位置i的下一位置a[i],i-1,i+1在bfs中属于同一层。

    注意(!):

    在bfs中起点不能是1,因为这样的话a[1]和2将被1更新并被加入队列,“更新”也就是1->a[1]使到达a[1]的最少步数f[a[1]]变为f[1]+1=0+1=1,同理1->2使得f[2]变为f[1]+1=1,答案显然是不对的(因为按此法要2步操作),所以起点1处有点特殊,不能用它来更新2(即不能从head=1(f[head]=0)开始进行bfs),所以我们从head=a[1](f[head]=1)开始进行bfs。

    AC代码:

     
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    int n;
    int a[100010];
    int f[100010];
    int vis[100010];
     
    void bfs(){
      queue<int > q;
      while(!q.empty()) q.pop();
      f[1]=0;
      vis[1]=1;
      int head=a[1];
      f[head]=1;
      vis[head]=1;
      q.push(head);
      while(!q.empty()){
        head=q.front();
        q.pop();
        if(!vis[a[head]]){
            vis[a[head]]=1;
            if(f[a[head]]>f[head]+1)
                f[a[head]]=f[head]+1;
            q.push(a[head]);
        }
        if(head-1>=1&&!vis[head-1]){
            vis[head-1]=1;
            if(f[head-1]>f[head]+1)
                f[head-1]=f[head]+1;
            q.push(head-1);
        }
        if(head+1<=n&&!vis[head+1]){
            vis[head+1]=1;
            if(f[head+1]>f[head]+1)
                f[head+1]=f[head]+1;
            q.push(head+1);
        }
      }
    }
     
     
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        memset(vis,0,sizeof(vis));
        memset(f,0x3f,sizeof(f));
        bfs();
        printf("%d
    ",f[n]);
        return 0;
    }

    总结:对于图论题,关键是等价建立图模型。

    转载请注明出处:https://www.cnblogs.com/lllxq/
  • 相关阅读:
    maven:读取程序版本号的三种方案
    有无目标的人生差10倍!赶紧和娃把新年计划做起来
    都怎么了,其实早就知道,但是一直没有找到答案……
    python添加tab键功能
    电影观后感
    ipset批量配置iptables
    Oracle 触发器,事物
    Oracle PL/SQL高级应用 视图 同义词 序列
    Oracle PL/SQL高级应用 存储过程
    Oracle PL/SQL高级应用 游标
  • 原文地址:https://www.cnblogs.com/lllxq/p/8432635.html
Copyright © 2020-2023  润新知