小明的跳格子
#include<cstring>//memcpy
#include<limits.h>//INT_MAX
#include<algorithm>//fill
#define MAX 505
using namespace std;
typedef struct MatGraph
{
long long int edge[MAX][MAX];
int n,e;
}MatGraph;
long long int dist[MAX];//最短路径
void Dijkstra(MatGraph g,int v)
{
int S[MAX]={0};//保存已加入S的集合
for(int i=0;i<g.n;i++)
{
dist[i]=g.edge[v][i];//距离初始化
S[i]=0;//一开始S里面空的
}
S[v]=1;//将v源点加入S集合
for(int i=0;i<g.n-1;i++)
{//去掉源点,到其他点的所有最短
int Min=INT_MAX/2,u;//u用来记录
for(int j=0;j<g.n;j++)
{//依托最近点,次最近点.....这样的已知信息序列合集来不断进行更新最短路径
//所以能够确保每轮递推找到的那个最短点是最终结果
if(S[j]==0&&dist[j]<Min)
{
u=j;
Min=dist[j];
}
}
S[u]=1;//纳入s集合了
for(int j=0;j<g.n;j++)
{
if(S[j]==0)
{//根据新加入的最短点作为中转点更新最短路径,INT_MAX一半是防止相加溢出
if(g.edge[u][j]!=INT_MAX/2&&dist[u]+g.edge[u][j]<dist[j])
{//保证有从新最短点到j的边,且经过它中转比原来的更短
dist[j]=dist[u]+g.edge[u][j];
}
}
}
}
}
long long int MAT[MAX][MAX];//中转的邻接矩阵数组
int main(void)
{
//a[i]=2则i可以直达j=2,那如果要到j=1,就要用一次魔法,到j=3没办法
//所以可以推测i->j的魔法代价为a[i]-j,为负数就是没法达,0就是直达
//我们基本不可能直接抵达终点,就要经过一系列中转点
//而且要求最少代价,就可以联想到Dijkstra求解最短路径,权重就为a[i]-j
int n;
scanf("%d",&n);
long long int a[n+5];
for(int i=0;i<n-1;i++)//小心a的个数是n-1
scanf("%lld",&a[i]);
MatGraph G;
G.n=n;
fill(MAT[0],MAT[0]+MAX*MAX,INT_MAX/2);//先初始化权重为无穷(/2防相加溢出)
for(int i=0;i<n-1;i++)
{//a只到n-1哦
for(int j=0;j<n;j++)
{//目的地当然不止到n-1
if(a[i]-j-1>=0)//负数当然不给它权重啦
MAT[i][j]=a[i]-j-1;//邻接矩阵赋值权重
//实际中记得补上1的差值对应回数组下标啦
}
}
memcpy(G.edge,MAT,sizeof(MAT));//复制到MatGraph里的邻接矩阵
Dijkstra(G,0);
if(dist[n-1]!=INT_MAX/2)
printf("%lld",dist[n-1]);
else
printf("-1");
return 0;
}