C - Unidirectional TSP (dp)

https://vjudge.net/contest/279505#problem/C

题目大意:

给一个n*m的矩阵 数字代表值,有三个方向移动,向右,右上,右下。可以从n行到第1行,也可以从第1行到第n行。求从第一列到最后一列所经过路程值的和,并打印路径(行数),要求字典序最小。

题目分析:

因为要求字典序最小,正推不好记录路径。所以采用逆推。

dp【i】【j】表示:第i行第j列得最小值。

dp【i】【j-1】=min(dp【i】【j-1】,dp【i-1】【j】+a【i-1】【j】,dp【i】【j】+a【i】【j】,dp【i+1】【j】+a【i+1】【j】);

枚举第一行得最小值便是答案。

路径记录难点:在更新值后,path【row【k】】【j-1】记录从第j列的哪一行来的。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int N=110;
int dp[N][N],a[N][N],path[N][N];
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		memset(dp,INF,sizeof(dp));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				scanf("%d",&a[i][j]);
				if(j==m)dp[i][m]=a[i][m];
			}
		}
		for(int j=m;j>1;j--){
			for(int i=1;i<=n;i++){
				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++){
					int tmp=dp[i][j]+a[row[k]][j-1];
					if(tmp<dp[row[k]][j-1])
					{
						dp[row[k]][j-1]=tmp;
						path[row[k]][j-1]=i;
					}
				}
			}
		}
		int p=INF,r;
		for(int i=1;i<=n;i++){
			if(p>dp[i][1]){
				r=i;
				p=dp[i][1];
			}
		}
		printf("%d",r);
		for(int i=path[r][1],j=1;j<m;j++,i=path[i][j])
		printf(" %d",i);
		printf("\n%d\n",p);
	}
		
}

猜你喜欢

转载自blog.csdn.net/qq_43490894/article/details/87555350
TSP