uva 116 单向tsp

题意:给一个n行m列的矩阵,要求从第 1 列走到第 m 列,路过每个点时将该点的权值加起来。从当前点走向下一点只能走右上、右、右下4个方向,并且图是环状的,从1向右上走会走到n,同理n向右下会走到1。求最小权值和,并输出路径,若权值相等,输出字典序小的那一种情况。

思路:紫书上的题,紫书上用递推的dp,我写了记忆化搜索的方法。实质是一样的,每次dfs保存当前节点的下一个最有路径。再通过 way[dir][i]访问。

#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 0x3fffffff
using namespace std;
typedef long long ll;
int n,m;
int dp[110][110];
int maze[110][110];
int way[110][110];

int dfs(int i,int j){
    int res = INF,dir = INF;
    if(dp[i][j]!=-1) return dp[i][j];

    else if(j == m ){
        return maze[i][j];
    }
    else{
        int dire[3];
        if(i == 1)
            dire[0] = n,dire[1] = i,dire[2] = i+1;
        else if(i == n)
            dire[0] = i-1,dire[1] = i,dire[2] = 1;
        else
            dire[0] = i-1,dire[1] = i,dire[2] = i+1;

        for(int t =0;t<3;t++){
            int nt = dfs(dire[t],j+1) + maze[i][j];
            if(res > nt)
                dir = dire[t],res = nt;
            else if(res == nt)
                dir = min(dir,dire[t]);
        }
    }
    way[i][j] = dir;
    return dp[i][j] = res;
}
int main()
{
    freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        for(int i =1;i<=n;i++)
            for(int j =1;j<=m;j++) scanf("%d",&maze[i][j]);

        int ans = INF,dir;
        if(n == 1){
            ans = 0;char ch;
            for(int i=1;i<=m;i++){
                ans+=maze[1][i];ch = i==m?'\n':' ';
                printf("%d%c",1,ch);
            }
            printf("%d\n",ans);

            continue;
        }
        memset(dp,-1,sizeof dp);
        for(int i =1;i<=n;i++){
            int now = dfs(i,1);
            if(now < ans){ans = now,dir = i;}
        }

        for(int i =1;i<=m;i++){
            char ch = i==m?'\n':' ';

            printf("%d%c",dir,ch);
            dir = way[dir][i];
        }
        printf("%d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值