大体题意:
给你一个n * m的数字矩阵,你从第一列任一行出发,到最后一列,只能横着走一个,斜上走一个,斜下走一个,求和最小值,并且行号的字典序最小?
思路:
令Dp[i][j]表示从矩阵 i,j位置出发,到最后一列的权值之和的最小值!
那么直接根据路的规则向前转移即可!
因为输出要字典序最小,所以先把能走的行号放到数组里,拍个序,保证字典序最小,在求最小值,然后利用链表 next[i][j]表示i,j位置的下一行!
自己wa了一次,需要注意到边界问题,就是n行1列的情况!
详细见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 11;
int a[maxn][maxn*10];
int dp[maxn][maxn*10];
int nest[maxn][maxn*10];
int main(){
int n, m;
while(scanf("%d %d",&n, &m) == 2){
memset(nest,-1,sizeof nest);
for (int i = 1; i <= n; ++i){
for (int j = 1; j <= m; ++j){
scanf("%d",&a[i][j]);
}
}
if (m == 1){
int ans = 1e9;
int pos;
for (int i = 1; i <= n; ++i){
if (a[i][1] < ans){
ans = a[i][1];
pos = i;
}
}
printf("%d\n%d\n",pos,ans);
continue;
}
for (int i = 1; i <= n; ++i){
dp[i][m] = a[i][m];
}
int ans = 0x3f3f3f3f,pos = -1;
for (int j = m-1; j >= 1; --j){
for (int i = 1; i <= n; ++i){
int row[3] = {i-1,i,i+1};
if (i == 1)row[0] = n;
if (i == n)row[2] = 1;
sort(row,row+3);
dp[i][j] = 0x3f3f3f3f;
for (int k = 0; k < 3; ++k){
int r = row[k];
if (dp[i][j] > dp[r][j+1] + a[i][j]){
dp[i][j] = dp[r][j+1] + a[i][j];
nest[i][j] = r;
}
}
if (j == 1){
if (ans > dp[i][1]){
ans = dp[i][1];
pos = i;
}
}
}
}
int i,j;
for (i = pos, j = 1 ; j <= m; i = nest[i][j],++j){
if (j > 1)printf(" ");
printf("%d",i);
}
printf("\n%d\n",ans);
}
return 0;
}