简单DP,难度在于路径的记录。
这里笔者用顺序的方法来递推,但这不方便记录,推荐使用逆序的方法。
这里需要注意一点的是,因为矩阵中的点可以是负数,所以不能用dp == -1或者一些其他的数据来判断是否访问过这个dp,当然你也可以预处理所有dp为1E18,或者像笔者一样用一个vis数组来判断。
#include <cstdio>
#include <cstring>
#define Min(x, y) (x <= y ? x : y)
const int MAXN = 100 + 5;
typedef long long ll;
int row, column;
ll matrix[MAXN][MAXN];
ll dp[MAXN][MAXN];
bool get_dp[MAXN][MAXN];
char perm[MAXN][MAXN][MAXN];
void solve()
{
memset(get_dp, false, sizeof(get_dp));
memset(dp, 0, sizeof(dp)); memset(perm, '\0', sizeof(perm)); for(int r = 0; r < row; r++) dp[r][0] = matrix[r][0], perm[r][0][0] = r + 1;
for(int c = 1; c < column; c++)
for(int r = 0; r < row; r++){
for(int i = -1; i <= 1; i++) if(dp[(r + row + i) % row][c - 1] + matrix[r][c] <= dp[r][c] || !get_dp[r][c]){
if(dp[(r + row + i) % row][c - 1] + matrix[r][c] == dp[r][c] && (perm[r][c][0] != '\0' && strcmp(perm[(r + row + i) % row][c - 1], perm[r][c]) >= 0)) continue;
dp[r][c] = dp[(r + row + i) % row][c - 1] + matrix[r][c], strcpy(perm[r][c], perm[(r + row + i) % row][c - 1]); perm[r][c][c] = r + 1; get_dp[r][c] = true;
}//printf("dp[%d][%d] = %lld, pre[%d][%d] = %d\n", r, c, dp[r][c], r, c, pre[r][c]);
}ll res = 1e18; bool vis = false;
for(int r = 0; r < row; r++){
if(!vis) res = dp[r][column - 1], vis = true; else res = Min(res, dp[r][column - 1]);
}char ans_perm[MAXN]; memset(ans_perm, '\0', sizeof(ans_perm)); ans_perm[0] = 255;
for(int r = 0; r < row; r++) if(res == dp[r][column - 1] && strcmp(perm[r][column - 1], ans_perm) < 0) strcpy(ans_perm, perm[r][column - 1]);
for(int i = 0; ans_perm[i]; i++){
if(i) printf(" "); printf("%d", ans_perm[i]);
}
printf("\n%lld\n", res);
}
bool init()
{
if(scanf("%d%d", &row, &column) != 2) return false;
for(int r = 0; r < row; r++)
for(int c = 0; c < column; c++) scanf("%lld", &matrix[r][c]); return true;
}
int main(void)
{
//freopen("test.txt", "w", stdout);
while(init()) solve();
return 0;
}