题目连接:116 Unidirectional TSP
题目大意:给出一个n * m的矩阵, 可以看成是 n 棵横着放的三叉树, 要求求所有路径中权值最小的, 并输出字典序最小的方案。
解题思路:状态转移方程:num[i][j] = max ( num[i - 1][j + 1], num[i - 1][j + 1], num[i - 1][j + 1]), 注意上下边界是相连,
然后rec[i][j]记录最优解选择的方向,整个的处理方向需要从前往后, 因为字典序要最小。
#include <stdio.h> #include <string.h> const int N = 105; int min (int a, int b) { return a < b ? a : b; } int n, m, sum, ans[N], num[N][N], rec[N][N]; void solve() { int k, t, a, i, c; memset(rec, -1, sizeof(rec)); for (int j = m - 1; j > 0; j--) { k = j + 1; for (int i = 1; i <= n; i++) { a = i - 1; if (a == 0) a = n; c = i + 1; if (c == n + 1) c = 1; if (num[a][k] <= num[i][k] && num[a][k] <= num[c][k]) { num[i][j] += num[a][k]; t = a; if (num[a][k] == num[i][k]) t = min(t, i); if (num[a][k] == num[c][k]) t = min(t, c); rec[i][j] = t; } else if (num[i][k] <= num[a][k] && num[i][k] <= num[c][k]) { num[i][j] += num[i][k]; t = i; if (num[i][k] == num[a][k]) t = min(t, a); if (num[i][k] == num[c][k]) t = min(t, c); rec[i][j] = t; } else { num[i][j] += num[c][k]; t = c; if (num[c][k] == num[a][k]) t = min(t, a); if (num[c][k] == num[i][k]) t = min(t, i); rec[i][j] = t; } } } sum = 1 << 30, t = 0; for (int i = 1; i <= n; i++) { if (num[i][1] < sum) { sum = num[i][1]; t = i; } } for (int i = 1; i < m; i++) { ans[i] = t; t = rec[t][i]; } ans[m] = t; } int main() { while (scanf("%d%d", &n, &m) == 2) { // Read; memset(num, 0, sizeof(num)); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) scanf("%d", &num[i][j]); } solve(); for (int i = 1; i < m; i++) printf("%d ", ans[i]); printf("%d\n%d\n", ans[m], sum); } return 0; }