Unidirectional TSP UVA - 116
给一个m行n列的证书矩阵,从第一列任何一个位置每次往右,又上或右下走一格,最终到达最后一列。要求经过的整数之和最小。整个矩阵是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行。输出路径上每列的行号。多解时,输出字典序最小的。
若不需要输出路径或任意输出一个路径,这就是水题一个。
但是要求输出字典序最小的解。
开始做是顺着遍历,每次记录pre是多少,dp数组表示第走到(i,j)时已经走的路程,但是这个过程中是有后效性的,所以无法确定最开始记录的是否是最优解,所以只能从后开始往前遍历,每次记录next,dp数组记录走到(i,j)时还要走的路程(或者说是倒着走的路程),这样后面的状态已经确定了,就可以保证记录的是最优解。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
const int maxn = 15, maxm = 110, inf = 0x3f3f3f3f;
int n, m;
int map[maxn][maxm];
int dp[maxn][maxm];
int nex[maxn][maxm];
int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
scanf("%d", &map[i][j]);
}
}
mem(dp, inf);
mem(nex, -1);
//dp[i][j]表示从坐标(i,j)出发到最后一列所需要的最小价值
for (int i = 1; i <= n; i++)
{
dp[i][m] = map[i][m];
nex[i][m] = 0;
}
for (int j = m - 1; j >= 1; j--)
{
for (int i = 1; i <= n; i++)
{
int temp[3] = {};
temp[0] = (i == 1 ? n : i - 1);
temp[1] = i;
temp[2] = (i == n ? 1 : i + 1);
sort(temp, temp + 3);
for (int k = 0; k < 3; k++)
{
if (dp[i][j] > map[i][j] + dp[temp[k]][j + 1])
{
dp[i][j] = map[i][j] + dp[temp[k]][j + 1];
nex[i][j] = temp[k];
}
}
}
}
/*for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
printf("%d%c", nex[i][j], j == m ? '\n' : ' ');
}
}*/
int ans = inf;
int pos = -1;
for (int i = 1; i <= n; i++)
{
if (ans > dp[i][1])
{
ans = dp[i][1];
pos = i;
}
}
printf("%d", pos);
for (int i = 1; i < m; i++)
{
printf(" %d", nex[pos][i]);
pos = nex[pos][i];
}
printf("\n%d\n", ans);
}
}