题意:
给一个m行n列(m<=10,n<=100)的整数矩阵,从第一列任何一个位置出发每次向右,右上或者右下走一格,要求经过的整数之和最小。整个矩阵是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行。输出路径上每一行的行号,要求字典序最小。
思路:
定义状态dp[i][j]为从第一列出发到第j列第i行的最小值是多少,转移方程上面已经给出,照着转移就行,难点在于字典序最小,因为我们定义的的dp方程是正向递推的,所以对于判断字典序最小有点麻烦,对于两个相等的结果,需要逆向找出他们的起点来判断字典序谁最小,在代码简洁程度上远不如lrj,但不失为一种思路。
代码:
#include <bits/stdc++.h> using namespace std; int mp[100][200],pre[100][200]; int ans[200];int n,m; void Debug() { printf("*********************************** "); for(int i = 1;i<=n;++i) { for(int j = 1;j<=m;++j) printf("%2d ",mp[i][j]); printf(" "); } } void check(int &a,int b,int &c,int j) { if(mp[b][j-1]<mp[a][j-1]) { a = b; c = mp[b][j-1]; } else if(mp[b][j-1]==mp[a][j-1]) { vector<int>t1(m+1),t2(m+1); int k = a; int i =j-1; while(i>=1) { t1[i] = k; k = pre[k][i]; --i; } k = b; i = j-1; while(i>=1) { t2[i] = k; k = pre[k][i]; --i; } for(int i = 1;i<j;++i) { if(t2[i]!=t1[i]) { if(t2[i]<t1[i]) { a = b; c = mp[b][j-1]; } return ; } } } return ; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&m)!=EOF) { for(int i = 1;i<=n;++i) { for(int j = 1;j<=m;++j) { scanf("%d",&mp[i][j]); pre[i][j] = -1; } } if(m==1) { int mi = mp[1][1],id = 1; for(int i = 1;i<=n;++i) { if(mp[i][1]<mi) { mi = mp[i][1]; id = i; } } printf("%d %d ",id,mi); continue; } for(int i = 2;i<=m;++i) { for(int j = 1;j<=n;++j) { int tmp = j; --tmp; if(tmp==0) tmp = n; int id = tmp,mi = mp[tmp][i-1]; // cout << "i = " << i << " " << " j = " << j << endl; //cout << id << " " << mi << endl; tmp = j, check(id,tmp,mi,i); tmp = j+1; if(tmp>n) tmp = 1; check(id,tmp,mi,i); mp[j][i]+=mi; pre[j][i] = id; } } //Debug(); for(int i =1;i<=m;++i) ans[i] = n; int mi = mp[1][m]; for(int i =2;i<=n;++i) mi = min(mi,mp[i][m]); for(int i =1;i<=n;++i) { if(mp[i][m]==mi) { vector<int> t(m+1); int k = i,j= m; while(j>=1) { t[j] =k; //--j; k = pre[k][j]; --j; } bool flag = false; for(int i = 1;i<=m;++i) { if(t[i]!=ans[i]) { if(t[i]<ans[i]) flag = true; break; } } if(flag) { for(int i =1;i<=m;++i) ans[i] = t[i]; } } } printf("%d",ans[1]); for(int i =2;i<=m;++i) printf(" %d",ans[i]); printf(" "); printf("%d ",mi); } return 0; }