一道很容易看出状态转移的DP。一共有n*m个状态,即对应格子走到最后的最小和。需要记录路径,还需要注意n或m为1的特殊情况。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#define INF 1000000
#define ll long long
#define min3(a,b,c) min(a,min(b,c))
using namespace std;
int mm[12][110];
int dp[12][110];
int path[12][110];
int main(){
int m,n;
while(cin>>m>>n){
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&mm[i][j]);
}
}
for(int i=1;i<=m;i++){
dp[i][n]=mm[i][n];
}
for(int i=n-1;i>0;i--){
for(int j=1;j<=m;j++){
if(j==1){
int tmp=min3(dp[m][i+1],dp[j][i+1],dp[j+1][i+1]);
dp[j][i]=mm[j][i]+tmp;
if(dp[j][i+1]==tmp){
path[j][i]=j;
}else if(dp[j+1][i+1]==tmp){
path[j][i]=j+1;
}else{
path[j][i]=m;
}
}else if(j==m){
int tmp=min3(dp[j-1][i+1],dp[j][i+1],dp[1][i+1]);
dp[j][i]=mm[j][i]+tmp;
if(dp[1][i+1]==tmp){
path[j][i]=1;
}else if(dp[j-1][i+1]==tmp){
path[j][i]=j-1;
}else{
path[j][i]=j;
}
}else{
int tmp=min3(dp[j-1][i+1],dp[j][i+1],dp[j+1][i+1]);
dp[j][i]=mm[j][i]+tmp;
if(dp[j-1][i+1]==tmp){
path[j][i]=j-1;
}else if(dp[j][i+1]==tmp){
path[j][i]=j;
}else{
path[j][i]=j+1;
}
}
}
}
int ans=INF;
int k;
for(int i=1;i<=m;i++){
if(dp[i][1]<ans)ans=dp[i][1],k=i;
}
if(m!=1){
for(int i=1;i<=n;i++){
cout<<k;
k=path[k][i];
if(i!=n)cout<<" ";
}
cout<<endl<<ans<<endl;
}else {
if(n==1){
cout<<1<<endl;
cout<<mm[1][1]<<endl;
}else{
int sum=0;
for(int i=1;i<=n;i++){
cout<<1;
if(i!=n)cout<<" ";
sum+=mm[1][i];
}
cout<<endl<<sum<<endl;
}
}
}
return 0;
}