本题的最短路与“数字三角形问题”的思路是极其相似的,最后一列为底层状态,从最后一列一列一列的向前更新。
主要是路径记录(尤其要求是字典序),再用一个数组path[][]
记录下父节点,最后循环输出。
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#define ms0(a) memset(a,0,sizeof(a))
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int inf = (1<<30)+1000;
int m,n,map[15][105],path[15][105],d[15][105];
int main(){
while(~scanf("%d%d",&m,&n))
{
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
d[i][j] = inf;
// ms0(path);
for(int j=n;j>=1;j--)
{
for(int i=1;i<=m;i++)
{
if(j==n) d[i][j]=map[i][j];
else{
int op[] = {i,i-1,i+1};
if(i==1) op[1]=m;
if(i==m) op[2]=1;
sort(op, op+3);//要排序,要求是字典序
for(int k=0;k<3;k++)
{
int cost = map[i][j]+d[op[k]][j+1];
if(cost<d[i][j])
{
d[i][j]=cost;
path[i][j]=op[k];
}
}
}
}
}
int ans = inf,first=0;
for(int i=1;i<=m;i++)
{
if(d[i][1]<ans)
{
ans=d[i][1];
first = i;
}
}
printf("%d",first);
for(int j=1,i=path[first][j];j<=n-1;i=path[i][++j])
{
printf("% d",i);
}
printf("\n%d\n",ans);
}
return 0;
}