[DAG动态规划][Uva 116 单向TSP]题目做题思路和收获

20 篇文章 0 订阅
4 篇文章 0 订阅

 

UVA 116

题目描述PDF

 

思路

这道题其实是一道特殊的DAG类动态规划;题目要求只能向右走,且只能向右上,右,右下三个方向,同时上部和下部是联通的;

 

1.动态规划求最小值

首先想到用DP[i][j]表示到达每一个点要用的最小的结果,动态转移方程为:

DP[i][j] = min{DP[i+1][j+1],DP[i-1][j+1],DP[i][j+1]} + Map[i][j];

其中,i表示行数,j表示列数。

由状态转移方程可知,在遍历j的时候需要逆推。

 

2.记录最优解路径

紫书上使用的方法是使用一个Next数组记录;Next[i][j]:表示在坐标为(i,j)的地方的下一个的行数。

在计算的时候动态更新,同时用一个First变量记录起点行数。

 

3.最小字典序

题目要求,当存在多个最优解的时候,输出最小字典序的最优解。

由于每一个阶段的时候有三个选择,可以将这三个选择(行数)记录,进行排序,从而保证解的最小字典序;

 

4.避开大坑

Uva 116的数据里有列数为1的数据,需要单独处理。

 

以下为AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int INF = 100000;

int M,N;

int Map[10+5][100+1] = {0};
int Next[10+5][100+1] = {0};
int DP[10+5][100+15] = {0};

//DP[i][j] = min{DP[i+1][j+1],DP[i-1][j+1],DP[i][j+1]} + Map[i][j];
//Next[i][j]:表示在坐标为(i,j)的地方的下一个的行数; 

int main(void)
{
    while(scanf("%d%d",&M,&N) != EOF)
    {
        for(int i = 1;i <= M;i++)
        {
            for(int j = 1;j <= N;j++)
            {
                cin >> Map[i][j];
            }
        }
        
        int First = 1;
        int ans = INF;
        
        //DP过程
        for(int i = 1; i <= M; i++)
        {
        	DP[i][N] = Map[i][N];
        }

        //注意数据中存在列数为1的超坑数据 
        if(N == 1)
        {
            for(int i = 1; i <= M; i++)
            {
                if(DP[i][1]<ans)
                {
                    ans = DP[i][1];
                    First = i; 
                }
            }
        }
        else //注意这里的顺序,顺序可以由DP方程推知 
        {
        	for(int j = N-1;j > 0;j--)
            {
                for(int i = 1;i <= M;i++)
                {
                    
                    DP[i][j] = INF;
                    int Rows[3] = {i-1,i,i+1};
                    
                    if(i == 1)
                    {
                        Rows[0] = M;
                    }
                    if(i == M)
                    {
                        Rows[2] = 1;
                    }
                    sort(Rows,Rows+3);
                    
                    for(int k = 0;k < 3;k++)
                    {
                        int Val = DP[Rows[k]][j+1] + Map[i][j];
                        if(Val < DP[i][j])
                        {
                            DP[i][j] = Val;
                            Next[i][j] = Rows[k];
                        }
                    }
                    
                    if(j == 1 && DP[i][j] < ans)
                    {
                        ans = DP[i][j];
                        First = i;
                    }
                }
            }
        }
        int r,j;
        printf("%d",First);
        for(int j=1,r=First;j<N;j++) 
        {
            r=Next[r][j];
            printf(" %d",r);
        }
        printf("\n%d\n",ans);
    }
    return 0;
}

学习知识点:动态规划路径记录与输出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值