您的位置:首页 > 其它

(UVA - 116)Unidirectional TSP(DP,多段图的最短路问题)

2017-08-14 16:50 435 查看
链接 : https://vjudge.net/problem/UVA-116

题意:给定m行n列(m<=10,n<=100)的整数矩阵,从第一列的任何一个位置出发每次往右或右上或右下走一格,最终到达最后一列。要求经过的整数之和最小。整个矩阵是环形的,即 第一行的上一行是最后一行,最后一行 的下一行是第一行。输出路径上的每列的行号。多解时输出字典序最小的。

分析:题目是紫书上的,P270. LRJ大神把这个分在 多阶段决策中的多段图的最短路问题中。

因为在本题中,每个阶段就是每一列,每个阶段都有三种决策:直行,右上,右下。

下面是我的理解,在本题中,因为终态是 最后一列,初态是 第一列。

DP做法,n,m的范围不大,设dp[i][j]: 从格子(i,j)出发到 最后一列的 最小整数和。 这种假设方法可以理解为最后一列为初态, 那么循环采用逆推的方法枚举列。

/* 若把dp[i][j] 设为: 从 第一列出发 到 最后一列的最小整数和,那么就顺推 枚举*/

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105;
const int INF=0x3f3f3f3f;
int a

,dp

;
int n,m,ne

;
void solve()
{
int 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
{
dp[i][j]=INF;///初始时  是一个不可能达到的值
int rows[]= {i,i-1,i+1};///三种决策
if(i==0) rows[1]=m-1;/// 第1行上面是最后一行
if(i==m-1) rows[2]=0;/// 最后一行下面是第一行,  符合题中 矩阵是环的规则
sort(rows,rows+3); ///对rows 重新排序,找到字典序最小
for(int k=0; k<3; k++)///通过对三种决策的试探,找到最小的那一个
{
int val=a[i][j]+dp[rows[k]][j+1];
if(dp[i][j]>val)///当前状态比下一个状态的 整数和要大
{
dp[i][j]=val;
ne[i][j]=rows[k];
}
}
}
if(j==0&&dp[i][j]<dp[first][j])///第一列
first=i;///first记录第一列的行号
}
}
printf("%d",first+1);
int j=1;
for(int i=ne[first][0]; j<n; i=ne[i][j],j++)
///ne记录行号,此处实现类似链表,因为循环中rows的处理,此处的输出一定是字典序最小(最小整数和相等的情况下)
printf(" %d",i+1);
printf("\n%d\n",dp[first][0]);////dp[first][0]就是题目要求的最小整数和
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
scanf("%d",&a[i][j]);
solve();
}
return 0;
}


题目读起来 很长,感觉啰嗦,有点迷糊,但是抓住题目的关键点: 起始在第一列的任意位置,矩阵是环形的,终态在最后一列,要求最小整数和, 那么是最短路问题,结合数据范围,可以采用DP,要求输出行号(字典序顺序)。用数组记录行号 感觉还是有迹可循,但是这还是清楚了之火才这样觉得。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp uva