UVa 116 - Unidirectional TSP(单向TSP)

题目:给你一个n*m的数字表格,找到一条从左到右的路径,使得上面的数字和最小。输出字典序最小的行号路径

           (每次可以从(i,j),走到(i,j+1),(i+1,j),(i-1,j)循环无限延伸没有边界)

思路:由于要输出字典序最小的路径,所以要逆向dp,边界在n列从右到左dp

说明:逆向dp保证字典序最小(后继最小),正向能保证每点前驱最小。

//0 KB 139 ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int r,c;
int mapp[15][150];
int next[15][150];
int dp[15][150];
int main()
{
    while(~scanf("%d%d",&r,&c)){
        memset(dp,0x3f,sizeof(dp));
        memset(next,0,sizeof(next));
        for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++){
            scanf("%d",&mapp[i][j]);
        }
        int ans=inf,head;
        for(int i=1;i<=r;i++){
            dp[i][c]=mapp[i][c];
            if(c==1){  //这里wa哭我了,忘记了初始化边界时候,列数可能就是1行,所以边界就是答案,所以初始化边界时候也要确定ans的值
                if(ans>dp[i][c]){
                    ans=dp[i][c];
                    head=i;
                }
            }
        }


        for(int i=c-1;i>0;i--)
        for(int j=1;j<=r;j++){
            int row[3];
            row[0]=j;
            row[1]=(j==r? 1: j+1 );
            row[2]=(j==1? r: j-1 ) ;
            sort(row,row+3);
            dp[j][i]=inf;
            for(int k=0;k<3;k++){
                if(dp[j][i]>dp[row[k] ][i+1]+mapp[j][i] ){
                    dp[j][i]=dp[row[k] ][i+1]+mapp[j][i];
                    next[j][i]=row[k];
                }
            }

            if(i==1){
                if(ans>dp[j][i]){
                    ans=dp[j][i];
                    head=j;
                }
            }

        }

        int path=head;
        printf("%d",path);

        for(int i=1;i<c;i++){
            path=next[path][i];
            printf(" %d",path);
        }
        printf("\n%d\n",ans);

    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值