DP 例9-4 Unidirectional TSP

给一个m行n列(m≤10,n≤100)的整数矩阵,从第一列任何一个位置出发每次往右、右
上或右下走一格,最终到达最后一列。要求经过的整数之和最小。整个矩阵是环形的,即第
一行的上一行是最后一行,最后一行的下一行是第一行。输出路径上每列的行号。多解时输
出字典序最小的。图9-5中是两个矩阵和对应的最优路线(唯一的区别是最后一行)。

数字三角形 + 打印路径
 

#include<bits/stdc++.h> 
#define ll long long 
using namespace std;
int m,n;
int a[1000][1000];
ll dp[1000][1000];
ll INF=1e18+7;
int num(int v,int n)
{
	return (v+n)%n;
} 

int main()
{
	while(~scanf("%d%d",&n,&m)) 
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				scanf("%d",&a[i][j]);
			}
		}
		
		for(int i=0;i<n;i++) dp[i][m-1]=a[i][m-1];//最后一列 初始化 
		
		for(int j=m-2;j>=0;j--)
		{
			for(int i=n-1;i>=0;i--)
			{
				dp[i][j]=INF;
				for(int k=-1;k<=1;k++)
				{
					dp[i][j]=min(dp[i][j],dp[num(i+k,n)][j+1]);//类似于数字三角形 
				}
				dp[i][j]+=a[i][j];
			}
		}
		ll anss=INF;
		for(int i=0;i<n;i++)
		{
			anss=min(anss,dp[i][0]);
		}
		int ind=0;
		for(int i=0;i<n;i++)
		{
			if(dp[i][0]==anss)
			{
				ind=i;//找出字典序最小 
				break;
			}
		}
		
		ll ans=anss-a[ind][0];
		printf("%d",ind+1);
		int jj=1;
		int ii=ind;
		while(jj!=m)
		{
			int b[4];
			int o=0;
			for(int i=-1;i<=1;i++) b[o++]=num(ii+i,n);
			sort(b,b+4);
			for(int i=0;i<3;i++)
			{
				if(dp[b[i]][jj]==ans)
				{
					printf(" %d",b[i]+1) ;
					ii=b[i];
					ans-=a[b[i]][jj];//依次找出下一个最小和所在位置 
					break;
					
				}
			}
			jj++;
		}
		printf("\n%lld\n",anss);
	}
}
发布了44 篇原创文章 · 获赞 6 · 访问量 1174

猜你喜欢

转载自blog.csdn.net/qq_43868883/article/details/103963738
TSP