题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=52
题目意思:
给你一个矩阵,让你求从第一列到最后一列的所有路径中值最小的那个,其中可以向上一行或当行或下一行走,其中最后一行和第一行可以看成相邻的。如果有多条值相同的路径,要求保证按字典顺序最小的输出路径。
解题思路:
从右向左依次动态规划,并保存路径。这样可以保证最后路径输出的是字典序最小的。
详见代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<stack> #include<queue> #define eps 1e-6 #define INF (1<<20) #define PI acos(-1.0) using namespace std; int save[15][120]; int dp[120][15],path[120][15],m,n; //dp[i][j]表示从最后一列到第i列第j行为止最小的值 //相应的path[i][j]表示到达第i列第j行的后一列的行数 int main() { while(scanf("%d%d",&m,&n)!=EOF) { memset(path,-1,sizeof(path)); memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++) { int j; for(j=1;j<n;j++) scanf("%d",&save[i][j]); scanf("%d",&save[i][j]); dp[j][i]=save[i][j]; //初始化 } for(int i=n-1;i>=1;i--) { //先考虑第一行的情况 dp[i][1]=dp[i+1][1]; //注意比较的顺序 path[i][1]=1; if(m>1&&dp[i+1][2]<dp[i][1]) //注意考虑只有一行的情况,m>1不能省略 { dp[i][1]=dp[i+1][2]; path[i][1]=2; } if(dp[i+1][m]<dp[i][1]) { dp[i][1]=dp[i+1][m]; path[i][1]=m; } dp[i][1]+=save[1][i]; for(int j=2;j<m;j++) //考虑第二行到倒数第二行的情况,此时情况都一样,可以统一处理 { dp[i][j]=dp[i+1][j-1]; path[i][j]=j-1; if(dp[i+1][j]<dp[i][j]) { dp[i][j]=dp[i+1][j]; path[i][j]=j; } if(dp[i+1][j+1]<dp[i][j]) { dp[i][j]=dp[i+1][j+1]; path[i][j]=j+1; } dp[i][j]+=save[j][i]; } dp[i][m]=dp[i+1][1]; //考虑最后一行的情况 path[i][m]=1; if(m>1&&dp[i+1][m-1]<dp[i][m]) //注意考虑只有一行的情况,m>1不能省略 { dp[i][m]=dp[i+1][m-1]; path[i][m]=m-1; } if(dp[i+1][m]<dp[i][m]) { dp[i][m]=dp[i+1][m]; path[i][m]=m; } dp[i][m]+=save[m][i]; } int sum=dp[1][1],begin=1; for(int i=2;i<=m;i++) //统计最少的那条路径 { if(dp[1][i]<sum) { sum=dp[1][i]; begin=i; } } printf("%d",begin); int temp=1; while(path[temp][begin]!=-1) //输出路径 { printf(" %d",path[temp][begin]); begin=path[temp][begin]; temp++; } printf("\n%d\n",sum); //输出最小的和 } return 0; }