UVa Problem 116 Unidirectional TSP (单向旅行商问题)

// Unidirectional TSP (单向旅行商问题)
// PC/UVa IDs: 111104/116, Popularity: A, Success rate: low Level: 3
// Verdict: Accepted
// Submission Date: 2011-10-12
// UVa Run Time: 0.252s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// [题目 PDF 文件下载地址]
// http://uva.onlinejudge.org/external/1/116.pdf
//
// [解题方法]
// 每个格子只能接受来自其左方、左上方、左下方走过来的路线,那么只要选择其中权和最小的路线,则当前
// 经过此格的路线的权和就是最小的,状态转移方程(使用格子本身来记录权和):
//
// matrix[i][j] += min{matrix[i][j - 1],matrix[i - 1][j - 1],matrix[i + 1][j - 1]}
//
// 简单的 DP,不过题目的条件加了一个小小的意外情况,第一行和最后一行可以相连,不过这并没有增加什么
// 难度,只需单独处理第一行和最后一行即可。注意:题目要求输出权和最小且字典序最小的路径,如果从左
// 往右进行 DP,虽然当每一列权和最小时行号都是最小,但是不能保证输出的是字典序最小的路径,反例如下:
//
// 3 4 1 2 8 6
// 1 2 8 2 1 1
// 5 9 3 9 9 5
// 1 1 1 3 1 1
// 3 7 2 8 6 4
//
// 如果是从左往右选权和最小的路径,则直接走第四行是权和最小的,但是字典序最小的却是 2 - 2 - 1 -
// 1 - 2 - 2,所以需要从右往左进行 DP,这样保证每一次都是权和最小,同时选择行号最小的以保证字典
// 序。因为题目给定的数不一定是正整数,虽然路径权和不会超过 30 个比特,但是列数最多有 100 列,故需
// 要考虑使用 long long 型整数。

#include <iostream>

using namespace std;

#define MAXLINE 11
#define MAXROW 101
#define MAXINT (1 << 30 - 1)

int main(int ac, char *av[])
{
	int line, row, tag, tmp;
	int successor[MAXLINE][MAXROW];
	long long matrix[MAXLINE][MAXROW];
	long long min;
	
	while (cin >> line >> row)
	{
		for (int i = 1; i <= line; i++)
			for (int j = 1; j <= row; j++)
				cin >> matrix[i][j];

		// 列优先处理,从倒数第二列开始处理,因为需要字典序最小的最小权和路径,如果从左
		// 往右处理,可以得到行号最小的权和方案,但是不一定是字典序最小的。
		for (int j = row - 1; j >= 1; j--)
		{
			for (int i = 1; i <= line; i++)
			{
				min = MAXINT;

				tmp = (i == 1 ? line : i - 1);
				if (min > matrix[tmp][j + 1])
				{
					min = matrix[tmp][j + 1];
					tag = tmp;
				}
				else if (min == matrix[tmp][j + 1] && tag > tmp)
					tag = tmp;

				if (min > matrix[i][j + 1])
				{
					min = matrix[i][j + 1];
					tag = i;
				}
				else if (min == matrix[i][j + 1] && tag > i)
					tag = i;

				tmp = (i == line ? 1 : i + 1);
				if (min > matrix[tmp][j + 1])
				{
					min = matrix[tmp][j + 1];
					tag = tmp;
				}
				else if (min == matrix[tmp][j + 1] && tag > tmp)
					tag = tmp;

				matrix[i][j] += min;
				successor[i][j] = tag;
			}
		}

		// 找权和最小的单元格。
		min = MAXINT;
		for (int i = 1; i <= line; i++)
			if (matrix[i][1] < min)
			{
				min = matrix[i][1];
				tag = i;
			}

		// 输出。
		cout << tag;
		int next = 1;
		int tmp = tag;
		while (next < row)
		{
			cout << " " << successor[tmp][next];
			tmp = successor[tmp][next];
			next++;
		}

		cout << endl;
		cout << matrix[tag][1] << endl;
	}

	return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值