记忆化搜索理解和最短路结合

A Walk Through the Forest HDU 1142

题目大意:有N个位置,办公室在1位置,家在2位置,给出M条双向边,现在需要从1到2,但是从A到B有一个条件就是,存在一条B到家的路径长度小于任意一条A到家的路径长度(即d[b]

第一次接触记忆化搜索这个东西,还是先感受一下大概的意思
1.斐波那契
非记忆化

ll F(ll x)if (x==1||x==2)
      return 1;
  else 
      return F(x-1)+F(x-2);

记忆化
dp数组用来“记忆”F(x)的值,如果已经算过了,那么就可以直接拿来用,也不用再一层层递归了,拿个例子来讲,辛辛苦苦算了F(50)和F(51),如果要算F(52),用记忆化搜索直接答案就出来了dp[52]=dp[50]+dp[51],但是如果不用记忆化就得再进行好多好多次的递归.

memset(dp,0,sizeof dp);
ll F(ll x)
{
    if (dp[x]!=0)
        return dp[x];
    if (x==1||x==2)
        return 1;
    return dp[x]=F(x-1)+F(x-2);
}

2.阶乘
非记忆化

ll fact(int x)
{
    if (x==1)
        return 1;
    return x*fact(x-1);
}

记忆化

memset(dp,0,sizeof dp);
ll fact(ll x)
{
    if (dp[x]!=0)
        return dp[x];
    if (x==1)
        return 1;
    return dp[x]=x*fact(x-1);
}

3.回归正题

我们现在可以先算出家(2)到其他点的最短距离,跑一个SPFA或者dijkstra即可,大不了套个板子就行了,然后用记忆化搜索的方法,dp[x]表示经过x一共有几条路径

int dfs(int x)
{
    if (x==2)
        return 1;//如果到达了2,那么就算是一条路径
    if (dp[x]!=0)
        return dp[x];//如果已经被算过了的话,就直接输出这个点的路径数量
    int cnt=0;
    for (int i=1; i<=n; i++)
    {
        if (cost[x][i]!=INF&&d[x]>d[i])
            cnt+=dfs(i);//如果这个点是没被算过的,那么就便利一遍与它相连且符合条件的点
    }
    return dp[x]=cnt;//这个加和就是最终这个点的路径数量,记忆一下
}

找了一下网上大神的解释,感觉解释的很好啊

int dfs(int x)
{
    if (dp[x]已经解得)
    {
        return dp[x];
    }
    else
    {
        初始化cnt;
        将dp[x]分解成很多个小问题的加和形式k1,k2,……kn;
        cnt+=dfs(k1)+dfs(k2)……;
             return dp[x]=cnt;
    }
}

总结一下,记忆化搜索可以减少一些不必要的计算,当数据范围比较大并且说有很多数据会重复计算的时候,用记忆化搜索可以大大增加效率

(虽然不知道下一次碰到能不能用上,但是至少稍微了解了一点菊部0.0)

你可能感兴趣的:(最短路问题)