单递推的话很简单们,可以正推和逆推,为了求出字典序最小,所以逆推比较好算,用ne存第i第j列 接下来走的是几行,找到起点就可以输出路径了。
代码
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int mod = 1e9+7;
const int N = 110;
int n,m;
int a[N][N],dp[N][N];
int ne[N][N],fi,ans = INF;
void print(){
cout<<fi;
for(int i=ne[fi][1],j=2;j<=m;i=ne[i][j],j++)
cout<<" "<<i;
cout<<"\n"<<ans<<endl;
}
void slove(){
for(int c=m;c>=1;c--)
for(int r=1;r<=n;r++){
if(c == m) dp[r][c] = a[r][c];
else
{
int row[] = {r-1,r,r+1};
if(r == 1) row[0] = n;
if(r == n) row[2] = 1;
sort(row,row+3);
dp[r][c] = INF;
for(int k=0;k<3;k++){
int v = dp[row[k]][c+1] + a[r][c];
if(v < dp[r][c]){
dp[r][c] = v;
ne[r][c] = row[k];//ne存的是当前这个点应该下列往哪行走
}
}
}
if(c == 1 && dp[r][c] < ans){
ans = dp[r][c];
fi = r;//存第一行最大的那个值
}
}
}
signed main(){
// IOS;
#ifdef ddgo
freopen("C:/Users/asus/Desktop/ddgoin.txt","r",stdin);
#endif
while(cin>>n>>m){
ans = INF;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
slove();
print();
}
return 0;
}