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

该博客介绍了如何应用动态规划解决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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值