Programming Challenges 习题11.6.4

PC/UVa:111104/116

Unidirectional TSP

典型的分阶段决策动态规划题目,需要记录的状态为当前列当前行的最小权和。

唯一麻烦的地方在于要输出字典序最小的路径,而不是任意路径,所以从左到右的递推只能保证逆向路径字典序最小,需要改成从右到左递推才能保证正向路径字典序最小。

#include <iostream>
#include <vector>
#include <array>
#include <climits>

using namespace std;

void rfindMinWeight(const vector<vector<int>> &Matrix, const int row, const int col)
{
	vector<vector<array<int, 2>>> Weight(col, vector<array<int, 2>>(row, array<int, 2>()));
	for (int r = 0; r < row; r++)
	{
		Weight[col - 1][r][0] = Matrix[r][col - 1];
		Weight[col - 1][r][1] = -1;
	}
	for (int c = col - 1; c > 0; c--)
	{
		int up, down;
		for (int r = 0; r < row; r++)
		{
			Weight[c - 1][r][0] = Weight[c][r][0];
			Weight[c - 1][r][1] = r;
			up = (r == 0 ? row - 1 : r - 1);
			if (Weight[c - 1][r][0] > Weight[c][up][0]){
				Weight[c - 1][r][0] = Weight[c][up][0];
				Weight[c - 1][r][1] = up;
			}
			else if (Weight[c - 1][r][0] == Weight[c][up][0]){
				if (up < Weight[c - 1][r][1]) Weight[c - 1][r][1] = up;
			}
			down = (r == row - 1 ? 0 : r + 1);
			if (Weight[c - 1][r][0] > Weight[c][down][0]){
				Weight[c - 1][r][0] = Weight[c][down][0];
				Weight[c - 1][r][1] = down;
			}
			else if (Weight[c - 1][r][0] == Weight[c][down][0]){
				if (down < Weight[c - 1][r][1]) Weight[c - 1][r][1] = down;
			}
			Weight[c - 1][r][0] += Matrix[r][c - 1];
		}
	}
	int minWeight = INT_MAX;
	int maxRow;
	for (int r = 0; r < row; r++)
	{
		if (Weight[0][r][0] < minWeight){
			minWeight = Weight[0][r][0];
			maxRow = r;
		}
	}
	vector<int> Path;
	for (int c = 0; c < col; c++)
	{
		Path.push_back(maxRow + 1);
		maxRow = Weight[c][maxRow][1];
	}
	for (size_t i = 0; i < Path.size() - 1; i++)
	{
		cout << Path[i] << ' ';
	}
	cout << Path.back() << endl;
	cout << minWeight << endl;
}

int main()
{
	int M, N;
	while (cin >> M >> N){
		vector<vector<int>> Matrix(M, vector<int>(N, 0));
		for (int m = 0; m < M; m++)
		{
			for (int n = 0; n < N; n++)
			{
				cin >> Matrix[m][n];
			}
		}
		rfindMinWeight(Matrix, M, N);
	}
	return 0;
}
/*
5 6
3 4 1 2 8 6
6 1 8 2 7 4
5 9 3 9 9 5
8 4 1 3 2 6
3 7 2 8 6 4
5 6
3 4 1 2 8 6
6 1 8 2 7 4
5 9 3 9 9 5
8 4 1 3 2 6
3 7 2 1 2 3
2 2
9 10 9 10
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值