由于要输出字典序最小,可以从倒着考虑dp直接求出字典序最小的路径。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 110
#define inf 0x3f3f3f3f
int g[maxn][maxn];
int next[maxn][maxn];
int dp[2][maxn];
int m,n;
int main(){
while(cin >>m>>n){
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&g[i][j]);
}
}
if(m==1){
int sum = 0;
for(int i=1;i<=n;i++) sum += g[1][i];
cout << 1;
for(int i=1;i<n;i++) cout <<" " <<1;
cout << endl << sum <<endl;
continue;
}
int t = 0;
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++) dp[t][i]=g[i][n];
for(int i=n-1;i>0;i--){
t^=1;
for(int j=1;j<=m;j++){
if(j==1) {
int a = min(dp[t^1][j],min(dp[t^1][j+1],dp[t^1][m]));
if(dp[t^1][j]==a) next[j][i] = j;
else if(dp[t^1][j+1]==a) next[j][i] = j+1;
else next[j][i] = m;
dp[t][j] = a+g[j][i];
}
else if(j==m){
int a = min(dp[t^1][1],min(dp[t^1][j-1],dp[t^1][j]));
if(dp[t^1][1]==a) next[j][i] = 1;
else if(dp[t^1][j-1]==a) next[j][i] = j-1;
else next[j][i] = j;
dp[t][j] =a+ g[j][i];
}
else{
int a = min(dp[t^1][j],min(dp[t^1][j+1],dp[t^1][j-1]));
if(dp[t^1][j-1]==a) next[j][i] = j-1;
else if(dp[t^1][j]==a) next[j][i] = j;
else next[j][i] = j+1;
dp[t][j] = a+ g[j][i];
}
}
}
int ans = inf;
int a ;
for(int i=1;i<=m;i++){
if(ans>dp[t][i]){
ans = dp[t][i];
a = i;
}
}
cout << a ;
for(int i=1;i<n;i++){
cout << " " <<next[a][i];
a = next[a][i];
}
cout <<endl <<ans <<endl;
}
return 0;
}