UVA 116 Unidirectional TSP(dp来一发)

题目链接: https://cn.vjudge.net/contest/306123#problem/B
在这里插入图片描述
在这里插入图片描述
题目解析:
(1)给一个m行n列(m≤10,n≤100)的整数矩阵,从第一列任何一个位置出发每次往右、右
上或右下走一格,最终到达最后一列。要求经过的整数之和最小。整个矩阵是环形的,即第
一行的上一行是最后一行,最后一行的下一行是第一行。输出路径上每列的行号。多解时输
出字典序最小的
在这里插入图片描述
在这里插入图片描述
(2)一个点可以推出三个状态是关键,同时还需要记录路径

1.如果是最后一列,每一点的状态直接等于它的权值大小

 if(j==m-1)//最后一列``
  dp[i][j]=st[i][j];

2.从正数第二列到倒数第二列,点扩张的时候要注意第一行和最后一行,比找到三个中的最小值

                int row[3]= {i,i-1,i+1}; //三个方向
                if(i==0) //第一行
                    row[1]=n-1;
                if(i==n-1)  //最后一行
                    row[2]=0;
                sort(row,row+3);
                dp[i][j]=inf;
                for(int k=0; k<3; k++)
                {
                    int v=st[i][j]+dp[row[k]][j+1];
                    if(dp[i][j]>v)
                    {
                        dp[i][j]=v;
                        next[i][j]=row[k];//从倒数第一列存到正数第二列,正数第一列没存

                    }

3.对第一列的判断

 if(j==0&&ans>dp[i][j])
 {
     ans=dp[i][j];
 	 first=i; //第一列最小权值的横坐标-1
 }

完整代码

#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], dp[30][300];  //a为地图
int nex[30][300];
void TSP(){
	int ans = inf, first = 0;
	for (int j = n - 1; j >= 0; j--) //从最后一列到第一列
	{
		for (int i = 0; i < m; i++){
			if (j == n - 1) //最后一列 
				dp[i][j] = a[i][j];  
			else{
				int row[3] = { i,i - 1,i + 1 }; //一个点可以从上一列的三个点扩展来 ,row[3]就是就是要输出的行值 
				if (i == 0)  //对环形的处理 
					row[1] = m - 1;
				if (i == m - 1)
					row[2] = 0;
				sort(row, row + 3);//先排序可以确保优先选择字典序小的行
				dp[i][j]=inf;
				for (int k = 0; k<3; k++)//这里求三种决策的最优解
				{
					int v=dp[row[k]][j+1] + a[i][j];
					if (dp[i][j]>v){
						dp[i][j] = v;
						nex[i][j] = row[k];
					}
				}
			}
				//printf("dp[i][j]的值为---->%d,坐标为(%d,%d)\n",dp[i][j],i,j);
			if(j==0&&ans>dp[i][j])//这里求从第一列的哪一行出发的最优解
			{
				ans = dp[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]);
		TSP();
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zaiyang遇见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值