单向TSP(unidirectional TSP,UVa 116)

问题:
给你一个n行m列的整数矩形,从第一列任何一个位置出发每次往右,右上或右下走一格,最终到达最后一列。要求经过的整数之和最小,整个矩形是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行,输出路径上每列的行号,多解时输出字典序最小的。
分析:
每一列就是一个状态,这个状态是由前一列的右上,右,右下得到的,要得到每个状态的最小值,只需比较右上,右,右下的最小值就好了。就得得到了下面的状态转移方程:

dp[i][j]=dp[i][j]+min(dp[i-1][j-1],dp[i][j-1],dp[i+1][j-1]);

在输出最小字典序的时候,可以采用之前用过的方法。
代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxx=10000;
int G[maxx][maxx];
int dp[maxx][maxx];
int n,m,ar[3];
int compare_min(int a,int b,int c)   //比较a,b,c中最小的一个
{
     ar[0]=a,ar[1]=b,ar[2]=c;
     sort(ar,ar+3);
     return ar[0];
}
int main()
{
     cin>>n>>m;
     for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
               cin>>G[i][j];
     for(int j=0,i=1;i<=n;i++)
          dp[i][j]=0;
     for(int j=1;j<=m;j++)
          for(int i=1;i<=n;i++)
          {
               if(i==1)
                    dp[i][j]=G[i][j]+compare_min(dp[n][j-1],dp[i][j-1],dp[i+1][j-1]);
               else if(i==n)
                    dp[i][j]=G[i][j]+compare_min(dp[i-1][j-1],dp[i][j-1],dp[1][j-1]);
               else
                    dp[i][j]=G[i][j]+compare_min(dp[i-1][j-1],dp[i][j-1],dp[i+1][j-1]);
          }
     int ans=(1<<30);
     for(int j=m,i=1;i<=n;i++)
          if(ans>dp[i][j])
               ans=dp[i][j];
     cout<<ans<<endl;
     int road[m],cns=0;
     for(int j=m;j>=1;j--)
     {
          for(int i=1;i<=n;i++)
          {
               if(dp[i][j]==ans)
               {
                    road[cns]=i;
                    break;
               }
          }
          ans=ans-G[road[cns]][j];
          cns++;
     }
     for(int i=m-1;i>=0;i--)
          cout<<road[i]<<" ";;
     cout<<endl;
     return 0;
}

感觉这个问题很简单,是自己独立想出来的,也是独立的写完了自己的代码,继续努力。书上的方法好像不一样我再研究一下。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值