题目大意:
输入一个m*n的矩阵,按每步走右上、右下、正右(三种选择)的方法,完成从第一列(任何行)走到最后一列。每步的消费是输入的矩阵元素值。注意,规定最后一行跟头一行是相邻的(即可以相互走到)。
要求输出 字典序最小(若有多种)的路径,路径用每步所在行表示。行列都从1开始计算。输入 1<=m<=10, 1<=n<=100。
输出结果不超出int32。
注意:①A path starts anywhere in column 1.
② lexicographically smallest should be output.
③The first and last rows (rows 1 and m) of a matrix are considered adjacent, i.e., the matrix ``wraps'' so that it represents a horizontal cylinder.
题目类型:dp
分析:
①做这题的时候正好碰到UvaOj崩溃(详见),很不爽。
之前的一直TEL,搞不懂神马情况(还把别人AC的代码拿来跟我的测速了,结果还是我的快啊!)。虽然开始的代码写得比较挫,但是复杂度神马的都没问题啊,难道漏了某个边界数据造成死循环?难道某些数据,我的寻路print_path的方法会耗很多时间?烦,暂时不想去理。
②把dp部分改了改,让它适合直接记录下一个结点的位置于next_row数组中(想节省掉打印路径的时间),然后就是无奈地等UvaOj从崩溃中wake up...我擦,它服务器至少崩溃了10多个小时吧。交了,AC了。很无奈,以后再说吧,烦死了。
代码:
#include<cstdio> #include<cstring> using namespace std; #define MAXM 12 #define MAXN 102 int a[MAXM][MAXN]; int d[MAXM][MAXN], vis[MAXM][MAXN]; //下标一律从1开始 int n, m; int next_row[MAXM][MAXN]; //!! #define INF 1<<30 int dp(int i, int j) { if(j > n) return 0; if(vis[i][j]) return d[i][j]; vis[i][j] = 1; int dir[3]; if(i == 1) dir[0] = 0, dir[1] = 1, dir[2] = -1; else if(i == m) dir[0] = 1, dir[1] = -1, dir[2] = 0; else dir[0] = -1, dir[1] = 0, dir[2] = 1; int min = INF; for(int k = 0; k<3; k++) { int t; int row=(m+i-1+dir[k])%m+1; //统一 使首尾行连接 min = min <= (t = dp(row, j+1)+a[i][j])? min : (next_row[i][j] = row, t); //逗号表达式取右值 } /* min = min < (t = dp(i, j+1)+a[i][j])? min : t; // i if(i == 1) min = min < (t = dp(m, j+1)+a[i][j])? min : t; //i-1 else min = min < (t = dp(i-1, j+1)+a[i][j])? min : t; if(i == m) min = min < (t = dp(1, j+1)+a[i][j])? min : t; //i+1 //!注意这里的条件结构 else min = min < (t = dp(i+1, j+1)+a[i][j])? min : t; */ return d[i][j] = min; } void print_path(int ibest) { printf("%d", ibest); //打印序号 int row = ibest; for(int j=1; j<n; j++) { row = next_row[row][j]; printf(" %d", row); } printf("/n"); } /* void print_path(int i, int j) { if(j>n) return; if(j == 1) printf("%d", i); //打印序号 else printf(" %d", i); if(i == 1) { //按字典序摆放 if(d[i][j] == a[i][j] + d[i][j+1]) print_path(i, j+1); //进入某一个,其他不会执行 else if(d[i][j] == a[i][j] + d[i+1][j+1]) print_path(i+1, j+1); else if(d[i][j] == a[i][j] + d[m][j+1]) print_path(m, j+1); } if(i == m) { if(d[i][j] == a[i][j] + d[1][j+1]) print_path(1, j+1); else if(d[i][j] == a[i][j] + d[i-1][j+1]) print_path(i-1, j+1); else if(d[i][j] == a[i][j] + d[i][j+1]) print_path(i, j+1); } if(i != 1 && i != m) { if(d[i][j] == a[i][j] + d[i-1][j+1]) print_path(i-1, j+1); //i-1 else if(d[i][j] == a[i][j] + d[i][j+1]) print_path(i, j+1); //i else if(d[i][j] == a[i][j] + d[i+1][j+1]) print_path(i+1, j+1); //i+1 } } */ int main() { while(scanf("%d%d", &m, &n) != EOF) { memset(vis, 0, sizeof(vis)); for(int i=1; i<=m; i++) for(int j=1; j<=n; j++) scanf("%d", &a[i][j]); int ans = INF; int ibest; int t; for(int i=1; i<=m; i++) ans = ans<=(t = dp(i, 1))? ans : (ibest=i, t); //!注意这里要<= 不然若有多个ibest,则取到的会是字典序最大的ibest了 //ans = ans<dp(i, 1)? ans : (ibest=i, dp(i, 1)); print_path(ibest); //printf("/n"); printf("%d/n", ans); } }