动态规划特训:单向TSP(UVA116多阶段决策)

解题思路:联系回溯法,使用阶段的思路,每一列相当于层数,可转移的三个状态为三棵子树,因此用一个二维数组dp[i][j]表示状态,其中j代表阶段(层数),在这里就是第几列,i表示行数。注意矩阵为环形,要做相应的处理,深入理解阶段的含义以及动态规划和回溯的关系。细节参见代码。

题目大意:从矩阵第一列的任一位置出发往右,可以直接往右,往右上或往右下,最终到达最后一列,整个矩阵为环形,第一行的上一行为最后一行,最后一行的下一行为第一行,要求经过的整数和最小,求最优路线。多解时输出字典序最小的。

picture37

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1<<30

int maze[11][101];
int dp[11][101];
int n,m;

void print(int x,int y)         //打印字典序最小的路径 
{
	cout<<x<<" ";
	if(y==m) {
		cout<<endl;
		return;
	}
	int row[3]={x-1,x,x+1};
	if(x==1) row[0]=n;       //注意这里的环形处理 
	if(x==n) row[2]=1;
	sort(row,row+3);         //因为要求输出字典序最小的,这里需要重新排序 
	for(int i=0;i<=3;i++)
	{
		if(dp[x][y]==dp[row[i]][y+1]+maze[x][y])
		{
			print(row[i],y+1);
			break;
		}
	}
}

int main()
{
	while(cin>>n>>m)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				cin>>maze[i][j];
			}
		}
		for(int i=1;i<=n;i++)     //边缘条件,到达最左边后需要加的整数 
		{
			dp[i][m]=maze[i][m];
		}
		for(int j=m-1;j>=1;j--)
		{
			for(int i=1;i<=n;i++)
			{
				dp[i][j]=inf;
				int row[3]={i-1,i,i+1};
				if(i==1) row[0]=n;
				if(i==n) row[2]=1;
				sort(row,row+3);
				for(int k=0;k<3;k++)
				{
					dp[i][j]=min(dp[i][j],dp[row[k]][j+1]+maze[i][j]);
				}
			}
		}
		int ans=inf,st=0;
		for(int i=1;i<=n;i++)
		{
			if(dp[i][1]<ans)
			{
				ans=dp[i][1];
				st=i;
			}
		}
		print(st,1);
		cout<<ans<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mavises/article/details/82078022
今日推荐