例题9-4 UVa116 Unidirectional TSP(DP:多段图的最短路)

题意:

看白书

要点:

一共三种决策:直行,右上,右下。那么就递推,注意题目中可以从第一列的任意一行出发,而且是环形的,最后还得按字典序输出路径,路径输出就直接用数组记录,因为是倒序递推,所以正序直接可以得到路径。


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m;
int a[30][300], d[30][300];
int nex[30][300];

void dp()
{
	int ans = inf, first = 0;
	for (int j = n - 1; j >= 0; j--)
	{
		for (int i = 0; i < m; i++)
		{
			if (j == n - 1)
				d[i][j] = a[i][j];
			else
			{
				int row[3] = { i,i - 1,i + 1 };
				if (i == 0)
					row[1] = m - 1;
				if (i == m - 1)
					row[2] = 0;
				sort(row, row + 3);//先排序可以确保优先选择字典序小的行
				d[i][j] = inf;
				for (int k = 0; k<3; k++)//这里求三种决策的最优解
				{
					int v = d[row[k]][j+1] + a[i][j];
					if (d[i][j]>v)
					{
						d[i][j] = v;
						nex[i][j] = row[k];//路径记录,因为是逆序的,所以反向就直接是正序
					}
				}
			}
			if (j == 0 && ans > d[i][j])//这里求从第一列的哪一行出发的最优解
			{
				ans = d[i][j];
				first = i;
			}
		}
	}
	printf("%d", first + 1);
	int i = nex[first][0];
	for (int j = 1; j < n; j++)//正序输出的就是路径
	{
		printf(" %d", i + 1);
		i = nex[i][j];
	}
	printf("\n%d\n", ans);
}
int main()
{
	while (scanf("%d%d", &m, &n) != EOF)//注意行列输入对应的m和n
	{
		for (int i = 0; i < m; i++)
			for (int j = 0; j < n; j++)
				scanf("%d", &a[i][j]);
		dp();
	}
	return 0;
}


posted @ 2016-05-15 12:00  seasonal  阅读(85)  评论(0编辑  收藏  举报