hdu 1142 A Walk Through the Forest(spfa+记忆化搜索)

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

题意:有n个点,m条边带权的无向图,点1为起点,点2为终点。求点1到点2有几条路,路的限制是每过一个点,都要后点到2的距离小于前点的距离。

 

思路:先用spfa/dijkstra算一遍每个点到2的最短距离。再搜索一下符合题意的路,普通的dfs是肯定超时的。这里用到记忆化搜索,用到动态规划的思想,dp[i]记录点i到2有几条符合题意的路。当搜索到已经搜索过的点,直接加就可以了,不用再搜。比如:3到2有2条路(即dp[3]=2),搜索4时,4和3连通,再搜索3时,dp[4]+=dp[3]。就不用重复操作。

记忆化搜索代码:

int dfs(int k){//返回几条符合的路 
    if(dp[k] > 0)    return dp[k];//dp初始值为0,已经搜索过,直接返回dp值 
    if(k == 2)    return 1;//搜索终点,搜索到2,说明这是条符合的路, 
    for(int i = head[k]; i != -1 ;i = edge[i].next){// 查找连通的点 
        int v = edge[i].to;
        if(d[k] > d[v])//符合要求,继续搜索直到搜索到2或已经搜索过 
            dp[k] += dfs(v);    
    }
    //cout<<k<<" "<<dp[k]<<endl;
    return dp[k];
}

 

完整代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
struct node{
    int from,to,w,next;
}edge[maxn*maxn];
int d[maxn],head[maxn*maxn],visit[maxn],dp[maxn];
int n,m,cnt;

void init(){//初始化 
    memset(head,-1,sizeof(head));
    memset(d,0x3f,sizeof(d));
    memset(visit,0,sizeof(visit));
    memset(dp,0,sizeof(dp));
    cnt=0;
}

void add(int u,int v,int w){//前向星连边 
    edge[cnt].from=u;
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

int dfs(int k){//返回几条符合的路 
    if(dp[k] > 0)    return dp[k];//dp初始值为0,已经搜索过,直接返回dp值 
    if(k == 2)    return 1;//搜索终点,搜索到2,说明这是条符合的路, 
    for(int i = head[k]; i != -1 ;i = edge[i].next){// 查找连通的点 
        int v = edge[i].to;
        if(d[k] > d[v])//符合要求,继续搜索直到搜索到2或已经搜索过 
            dp[k] += dfs(v);    
    }
    //cout<<k<<" "<<dp[k]<<endl;
    return dp[k];
}

void spfa(){//spfa求到2的最短路 
    queue<int> q;
    q.push(2);
    visit[2]=1;
    d[2]=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        visit[u]=0;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            int w=edge[i].w;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                if(!visit[v]){
                    visit[v]=1;
                    q.push(v);
                }
            }
        }
    }
}

int main(){
    while(scanf("%d",&n)!=EOF&&n){
        init();
        scanf("%d",&m);
        int u,v,w;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);//无向图 
            add(v,u,w);
        }
        spfa();
        printf("%d\n",dfs(1));
    }
    return 0;
}
View Code

 

posted @ 2019-01-20 13:47  怀揣少年梦.#  阅读(141)  评论(0编辑  收藏  举报