hdu 1142 最短路+记忆化深搜---好题

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

题意:他的办公室用1表示,家用2 表示,从1到2,中间可能会经过其它节点,而该节点可走的原则是:假设他此时在A处,B与其相邻,只有当B到2 路线中存在一条比A到2 的任意一条路径都短的路径,才能走B。问这样的路线有多少种?

分析:记忆化搜索不太会,这题难度就在这里。有挑战好玩。下面是大神的分析。欣赏下。

题目大意:寻找一共有多少条符合题意的路。能够从点A走到点B的要求是:点A到终点的最短路 > 点B到终点的最短路。 也就是说:从终点出发,求每一个点的最短路,然后那些最短路的值记录起来,作为能否通过的判断条件最后用记忆化搜索来搜索出一共多少条符合要求的路。普通的dfs是超时的,bfs是超内存的。

http://gzhu-101majia.iteye.com/blog/1151203

分析2:

做这题真可谓是一波三折, 足足WA了有30+次。

1.  题目意思懂得错误。题目中的一段话没懂得好:

  He considers taking a path A to B to be progress if there exists a route B to his home that is shorter than any possible route A. 

    这句话的意思是说,对于两点A,B, 若是点B达到家里的最短路间隔小于点A达到家里的最短路间隔,那么点A就可以达到点B。

    而我把这题懂得成了求有办公室到家里有几许条不合的最短路。

 

2.  解决了上述错误之后,接下来可以求出每一点达到点2(家里)的最短路,然后按照所求的各点最短路,求出有几许条到家里的路径。

     若是直接搜刮是会超时的,所以要用记忆化搜刮。

 

3.  因为本身的粗心, 因为我的法度中有两个数组名为d和dp, 在写记忆话搜刮时把这两个数组混合了,成果又WA了十多次而找不到原因。

http://www.cesclub.com/bw/jishuzhongxin/bianchengyuyan/2012/1017/44129.html

 

分析3:  设定一个DP数组,DP[i] 表示第i点到点2有多少种符合条件的走法。然后用递归的方法从1点求出到2点的符合条件的走法。具体思想看代码。

http://blog.csdn.net/xiezefan/article/details/7910991

View Code
// I'm lanjiangzhou
//C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <time.h>
//C++
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cctype>
#include <stack>
#include <string>
#include <list>
#include <queue>
#include <map>
#include <vector>
#include <deque>
#include <set>
using namespace std;

//*************************OUTPUT*************************
#ifdef WIN32
#define INT64 "%I64d"
#define UINT64 "%I64u"
#else
#define INT64 "%lld"
#define UINT64 "%llu"
#endif

//**************************CONSTANT***********************
#define INF 0x3f3f3f3f

// aply for the memory of the stack
//#pragma comment (linker, "/STACK:1024000000,1024000000")
//end

#define maxn 1010
int n,m;
int edge[maxn][maxn];
int S[maxn];
int dis[maxn];
int path[maxn];
int dp[maxn];

void dijkstra(int v0){
    //初始化
    for(int i=0;i<n;i++){
        dis[i]=edge[v0][i];
        S[i]=0;
        if(i!=v0&&dis[i]<INF) path[i]=v0;
        else path[i]=-1;
    }
    S[v0]=1;  dis[v0]=0;
    //从顶点v0确定n-1条最短路径
    for(int i=0;i<n-1;i++){
        int min=INF,  u=v0;
        //选择当前集合T中具有最短路径的顶点u
        for(int j=0;j<n;j++){
           if(!S[j]&&dis[j]<min){
               u=j;
               min=dis[j];
           }
        }
        S[u]=1;
        //修改T集合中顶点的dist和path数组元素值
        for(int k=0;k<n;k++){
            if(!S[k]&&edge[u][k]<INF&&dis[u]+edge[u][k]<dis[k]){
                dis[k]=dis[u]+edge[u][k];
                path[k]=u;
            }
        }
    }
}

//记忆化深搜
int dfs(int v){
    if(dp[v]!=-1){//该点已经走过,返回:过该点有多少条路
        return dp[v];
    }
    if(v==1 ) return 1;//找到终点,返回1(1条路)
    int sum=0;
    for(int i=0;i<n;i++){
        //有路相通而且要去的i点到终点站的距离要比v到终点站的距离小
        if(edge[v][i]!=INF&&dis[v]>dis[i]){
            int t=dfs(i);
            sum+=t;
        }
    }
    dp[v]=sum;
    return sum; //返回:该点一共可以有多少条路
}

int main(){
    int u,v,w;
    while(scanf("%d",&n)!=EOF){
        if(n==0 )  break;
        scanf("%d",&m);
        //初始化
        for(int i=0;i<n;i++){
            dp[i]=-1;
            for(int j=0;j<n;j++){
                if(i==j) edge[i][j]=0;
                else edge[i][j]=INF;
            }
            //if(i==j)  edge[i][j]=0;
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&w);
            u--;
            v--;
            edge[u][v]=w;
            edge[v][u]=w;
        }
        //求出各点到终点站的最短距离(终点作为起点)
        dijkstra(1);
        printf("%d\n",dfs(0));
    }
    return 0;
}

 

posted @ 2013-04-06 20:42  南下的小程序员  阅读(176)  评论(0编辑  收藏  举报