UVA 116 Unidirectional TSP(dp来一发)

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

题目链接: 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;
}

猜你喜欢

转载自blog.csdn.net/lylzsx20172018/article/details/92010875