HDU 1142 A Walk Through the Forest(Dijkstra+Dfs(第一次用记忆化搜索))

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1142

 

题意:这题的题意很重要,起点是1,终点是2,现在主人公已经知道,所有边的长度,然后他开始选择走不走某条边了。。

对于图中的每条边(A,B),他选这条边的前提是:存在一条B到终点的路径,比所有从A道终点的路径都短(即只要B到2的最短路径比A到2的最短路径短就存在了),选择完所有可以走的边后,问一共有多少条从1到2的路径

 

 

因为对于每条边(A,B)都要知道A到2的最短路和B到2的最短路,对于每个点都用Dijkstra的话O(n^3)超时,注意到,每次都是和2的最短路,所以灵活点,以2为起点用以次Dijkstra就可以求出所有结果。

 

然后用深搜,搜出所有的边,但是会超时,所以要用到记忆化搜索,要用辅助数组来保存结果,ans[now]表示now到终点一共有多少条路。开始初始化为0。。。。。由于某个点,可能有多条路经过,用了记忆化搜索,当不是第一次经过的时候,ans[now]已经有答案了。。。。要特别注意的是这里其实根本不需要用vis[]来标记有每走过,ans[now]已经记录了有每走过了。。。。。。。这里跟Dfs中for里vis[]区分开来。。。。。

 

记忆化搜索是为了避免重复做同一件事(这题是为了避免重复计算某点到终点的路径数)

 

而,深搜for里的vis[]是为了当从另一条路经过该点时能够经过。。

 

代码:

#include <iostream>

#include <vector>

using namespace std;



const int M = 1111;

const int INF = 1 << 30;



int d[M];

int g[M][M];

bool used[M];

//bool vis[M];

int ans[M];

int compare;

int n, m;







//vector <int> gg[1010];





void D(int star)//记录所有到2的最短路径

{

    for (int i = 1; i <= n; i++)

    {

        d[i] = INF;

    }

    memset(used, 0, sizeof(used));



    d[star] = 0;

    for (int cnt = 0; cnt < n; cnt++)

    {

        int  min = INF;

        int min_num = 0;

        for (int i = 1; i <= n; i++)

        {

            if (!used[i] && min > d[i])

            {

                min = d[i];

                min_num = i;

            }

        }



        used[min_num] = 1;



        for (int i = 1; i <= n; i++)

        {

            if (!used[i] && d[i] > d[min_num] + g[min_num][i])

            {

                d[i] = d[min_num] + g[min_num][i];

            }

        }



    }

}





int Dfs(int now)

{

    if (ans[now])

    {

        return ans[now];

    }

    if (now == 2)

    {

        return 1;

    }



    for (int i = 1; i <= n; i++)

    {

        if (/*!vis[i]  && */g[now][i] != INF && d[now] > d[i])

        {

            

            ans[now] += Dfs(i);

        }

    }

    return ans[now];

}





int main()

{

    



    while (scanf("%d", &n), n)

    {

    for (int i = 1; i <= n; i++)

    {

        for (int j = 1; j <= n; j++)

        {

            g[i][j] = INF;

        }

    }



        scanf("%d", &m);

                

        while (m--)

        {

            int a, b, c;

            scanf("%d%d%d", &a, &b, &c);



            g[a][b] = g[b][a] = c;

        }



        D(2);

        memset(ans, 0, sizeof(ans));//ans[i]表示i道终点路径的条数

        //memset(vis, 0, sizeof(vis));

        //vis[1] = 1;

        printf("%d\n", Dfs(1));

    }

    return 0;

}

 

你可能感兴趣的:(dijkstra)