UVA116
题解:
- 参考刘汝佳的代码。每次从最后一列开始往前推。dp[i][j]表示从(i,j)到最后一列的整数和最小值。因为每次只能直行,右上,右下。所以dp[i][j] = max(dp[i][j+1],dp[i+1][j+1],dp[i-1][j+1])。
- 但是事情没有这么简单因为第一行的上面是最后一行,最后一行的下面是第一行。所以这里我们再开一个数组row[3],记录3个行,所以dp[i][j] = max(dp[row[0]][j+1],dp[row[1]][j+1],dp[row[2]][j+1])。
- 但是还没有结束,因为字典序要最小,所以对row排个序就解决了。
- 求路线就是开个next数组,每次遇到更优路线记录一下。
代码:
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int const N = 10 + 5;
int const M = 100 + 5;
int const inf = 0x7f7f7f7f;
int mp[N][M],dp[N][M],ne[N][M]; //dp[i][j]表示在(i,j)到终点的最小值
int n,m;
void solve(){
int ans = inf,first;
for(int j=m;j>=1;j--){
for(int i=1;i<=n;i++){
if(j == m) dp[i][j] = mp[i][j];
else{
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] = inf;
for(int k=0;k<3;k++){
int v = dp[row[k]][j+1] + mp[i][j];
if(v < dp[i][j]) {dp[i][j] = v; ne[i][j] = row[k];}
}
}
if(j == 1 && dp[i][j] < ans) {ans = dp[i][j]; first = i;}
}
}
for(int i=first,j=1;j<=m;i=ne[i][j],j++) //先next,在j++
printf("%d%c",i,j!=m?' ':'\n');
printf("%d\n",ans);
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
solve();
}
return 0;
}