UVA - 116 - Unidirectional TSP(DAG上的动态规划)
题意:给定一个n行m列的矩阵(n <= 10,m <= 100),从第一列到最后一列,设目前在(i, j),每次可走到下一列的(i - 1, j + 1),(i, j + 1),(i + 1, j + 1)位置,矩阵的第一行与最后一行是循环的(最后一行往下是第一行,第一行往下是最后一行),求第一列到最后一列的一条路径使权值和最小,并且打印出此条路径中,经过每一列的行的下标,若有多解,则让这个下标序列的字典序最小。
设d[i][j]为从后往前到(i, j)时权值最小的和,则对于每一格(i, j),向前研究它的三个方向,研究的时候需要注意:
1、三个方向的格子中要取最小的d与a[i][j]相加得d[i][j];
2、若有相同的数值,则取下标最小的(可以先将三个方向的下标放在一个数组里然后排序即可);
3、对每一格,记录它是由后一列的哪一格得来的,以便打印路径。
即d[i][j] = Min(d[i - 1][j + 1], d[i][j + 1], d[i + 1][j + 1]) + a[i][j];
代码如下:
#include<cstdio> #include<cstring> #include<cctype> #include<cstdlib> #include<cmath> #include<iostream> #include<sstream> #include<iterator> #include<algorithm> #include<string> #include<vector> #include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<list> #define fin freopen("in.txt", "r", stdin) #define fout freopen("out.txt", "w", stdout) #define pr(x) cout << #x << " : " << x << " " #define prln(x) cout << #x << " : " << x << endl #define Min(a, b) a < b ? a : b #define Max(a, b) a < b ? b : a typedef long long ll; typedef unsigned long long llu; const int INT_INF = 0x3f3f3f3f; const int INT_M_INF = 0x7f7f7f7f; const ll LL_INF = 0x3f3f3f3f3f3f3f3f; const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f; const double pi = acos(-1.0); const double EPS = 1e-6; const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1}; const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1}; const ll MOD = 1e9 + 7; using namespace std; #define NDEBUG #include<cassert> const int MAXN = 100 + 10; const int MAXT = 10000 + 10; int n, m, a[15][MAXN], d[15][MAXN], nex[15][MAXN]; int main(){ while(scanf("%d%d", &n, &m) == 2){ memset(a, 0, sizeof a); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j]); memset(d, INT_INF, sizeof d); for(int i = 1; i <= n; ++i) d[i][m] = a[i][m]; memset(nex, 0, sizeof nex); for(int j = m - 1; j >= 1; --j) for(int i = 1; i <= n; ++i){ int k[] = {i, i - 1, i + 1}; if(k[1] == 0) k[1] = n; if(k[2] == n + 1) k[2] = 1; sort(k, k + 3); for(int u = 0; u < 3; ++u){ int &lur = k[u]; if(d[lur][j + 1] + a[i][j] < d[i][j]){ d[i][j] = a[i][j] + d[lur][j + 1]; nex[i][j] = lur; } } } int mi = INT_INF, lur; for(int i = 1; i <= n; ++i) if(d[i][1] < mi){ mi = d[i][1]; lur = i; } int sum = 0; for(int j = 1, i = lur; j <= m; i = nex[i][j], ++j){ if(j != 1) printf(" "); printf("%d", i); sum += a[i][j]; } printf("\n%d\n", sum); } return 0; }