Unidirectional TSP UVA - 116

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);
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值