uva 116 (记忆化搜索)

本文介绍了一种基于动态规划的最短路径算法实现方法,通过状态转移方程找到从起点到终点的权值最小路径,并记录字典序最小的路径。适用于网格状地图寻路问题。

题意:


如图,从左到右走,每次可以往左上(up)左(fo)左下(dn)走,当走到第一行或最后一行时可以如图穿越。

求一条权值最小的路径,并打印字典序最小的路径。


解析:

状态转移方程:

dp[ i ][ j ] = min( dp[ (i - 1 + m) % m ] [ j + 1 ],    //up

                            dp[ i ] [ j + 1],                               //fo

                            dp[ ( i + 1) % m ] [ j + 1] )          //dn


字典序最小的路径也在记忆化搜索中更新,详见代码。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;

const int maxr = 10 + 10;
const int maxc = 100 + 10;
const int inf = 0x3f3f3f3f;

int g[maxr][maxc];
int path[maxr][maxc];
int dp[maxr][maxc];
int m, n;

int dfs(int i, int j)
{
    if (n <= j)
        return 0;
    if (dp[i][j] != inf)
        return dp[i][j];
    int up = dfs((i - 1 + m) % m, j + 1);
    int fo = dfs(i, j + 1);
    int dn = dfs((i + 1) % m, j + 1);

    int minn = up;
    if (fo < minn)
        minn = fo;
    if (dn < minn)
        minn = dn;

    int dir = inf;
    if (minn == up)
        dir = min(dir, (i - 1 + m) % m);
    if (minn == fo)
        dir = min(dir, i);
    if (minn == dn)
        dir = min(dir, (i + 1) % m);

    dp[i][j] = minn + g[i][j];
    path[i][j] = dir;
    return dp[i][j];
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    while (scanf("%d%d", &m, &n) != EOF)
    {
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                scanf("%d", &g[i][j]);
                dp[i][j] = inf;
            }
        }
        int ans = inf;
        int pos = -1;
        for (int i = 0; i < m; i++)
        {
            int t = dfs(i, 0);
            if (t < ans)
            {
                ans = t;
                pos = i;
            }
        }
        printf("%d", pos + 1);
        pos = path[pos][0];
        for (int i = 1; i < n; i++)
        {
            printf(" %d", pos + 1);
            pos = path[pos][i];
        }
        printf("\n%d\n", ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值