vijos P1006 晴天小猪历险记之Hill SPFA

背景

在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳、勇敢、善良、团结……
不过有一天,最小的小小猪生病了,而这种病是极其罕见的,因此大家都没有储存这种药物。所以晴天小猪自告奋勇,要去采取这种药草。于是,晴天小猪的传奇故事便由此展开……

描述

这一天,他来到了一座深山的山脚下,因为只有这座深山中的一位隐者才知道这种药草的所在。但是上山的路错综复杂,由于小小猪的病情,晴天小猪想找一条需时最少的路到达山顶,但现在它一头雾水,所以向你求助。

山用一个三角形表示,从山顶依次向下有1段、2段、3段等山路,每一段用一个数字T(1<=T<=100)表示,代表晴天小猪在这一段山路上需要爬的时间,每一次它都可以朝左、右、左上、右上四个方向走。山是环形的。(**注意**:在任意一层的第一段也可以走到本层的最后一段或上一层的最后一段)。

晴天小猪从山的左下角出发,目的地为山顶,即隐者的小屋。

★★★**本题为vijos早年陈题,描述晦涩,现重新描述题面如下**★★★
有一个数字三角形,共nn行,依次编号为第一行,第二行至第nn行。其中第ii行有ii个数字,位置依次记为(i,1),(i,2)(i,1),(i,2)到(i,i)(i,i)。
现在从第nn层的第一个位置出发(即(n,1)(n,1)),每一步移到相邻的,且行编号小于或等于当前行编号的一个位置中,直到(1,1)(1,1)结束,在不重复经过任何位置的情形下,路过的所有位置(包括端点)的对应数字之和最小。

下面详细定义相邻关系。
同一层内连续的两个位置相邻,特别的有每一层第一个位置与最后一个位置相邻。
对于位置(i,j)(i,j),它与(i-1,j-1)(i1,j1)以及(i-1,j)(i1,j)相邻,特别的(i,1)(i,1)与(i-1,i-1)(i1,i1)相邻,且(i,i)(i,i)与(i-1,1)(i1,1)相邻。

格式

输入格式

第一行有一个数n(2<=n<=1000),表示山的高度。

从第二行至第n+1行,第i+1行有i个数,每个数表示晴天小猪在这一段山路上需要爬的时间。

输出格式

一个数,即晴天小猪所需要的最短时间。

样例输入

5
1
2 3
4 5 6
10 1 7 8
1 1 4 5 6

样例输出

10

限制

各个测试点1s

该题可用最短路求解,首先构图,用一个新数组记录输入的val的序号,便于后续的加边和SPFA,之后跑一遍最短路求左下角点到顶点的最短路即为答案。构图中,边的权值可设为出边点的val,答案为dis[h[1][1]]+t[1][1],具体事项通过代码理解。

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define M 5*N
#define N 505000 
#define Max 1100
using namespace std;
queue<int>q;
int nxt[M],head[N],to[M],val[M],tot;
int t[Max][Max],h[Max][Max];
int n;
int dis[N];
bool check[N];
void Add(int x,int y,int z)
{
    val[++tot]=z;
    to[tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void SPFA()
{
    memset(dis,0x3f3f,sizeof(dis));
    dis[h[n][1]]=0;
    q.push(h[n][1]);
    check[h[n][1]]=1;
    while(!q.empty())
    {
        int k=q.front(),y;
        q.pop();
        check[k]=0;
        for(int i=head[k];i;i=nxt[i])
        {
            if(dis[y=to[i]]>dis[k]+val[i])
            {
                dis[y]=dis[k]+val[i];
                //printf("y=%d\n",y);
                if(check[y]==0)
                {
                    q.push(y);
                    check[y]=1;
                }
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            scanf("%d",&t[i][j]);
            h[i][j]=++cnt;
        }
    }
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(j==1)
            {
                Add(h[i][j],h[i-1][i-1],t[i][j]);//左上
                Add(h[i][j],h[i][i],t[i][j]);//
            }
            else 
            {
                Add(h[i][j],h[i-1][j-1],t[i][j]);//左上
                Add(h[i][j],h[i][j-1],t[i][j]);//
            }
            if(j==i)
            {
                Add(h[i][j],h[i-1][1],t[i][j]);//右上
                Add(h[i][j],h[i][1],t[i][j]);//
            }
            else
            {
                Add(h[i][j],h[i-1][j],t[i][j]);//右上
                Add(h[i][j],h[i][j+1],t[i][j]);//
            }
            
        }
    }
    SPFA();
    
    printf("%d\n",dis[h[1][1]]+t[1][1]);
    return 0;
}
/*for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            printf("dis[h[%d][%d]]=%d\n",i,j,dis[h[i][j]]);
        }
    }
*/
View Code

 

 
posted @ 2020-08-06 00:00  寻幽  阅读(127)  评论(0)    收藏  举报