HDU-1142-最短路+记忆化搜索

首先来弄清楚题意:如果从A、B两点相连接,并且B点到终点距离小于A点到终点的距离,那么就走A->B这段路,问你最后有多少种不同的路线到达终点。

根据题意能够知道,只有离终点越近的路段才能走,例如第一个样例里面,1->4可以走,但是1->3不可以走,因为1到终点距离是36,要小于3到终点的距离37。

那么我们可以先从终点跑一遍最短路,然后再从起点开始选择路径,看按照每走一段路就离终点越近的规则,能有多少条路到达终点。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <iomanip>
#include <string>

using namespace std;

const int maxn=1e3+5;
const int INF=0x3f3f3f3f;
int n,m,a,b,val;
struct P{
    int to,cost;
    bool operator<(const P&a)const{
        return cost>a.cost;
    }
};
vector<P> edge[maxn];
int dis[maxn],vis[maxn],sum[maxn];
void ini(){
    for(int i=0;i<maxn;i++) edge[i].clear();
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(sum,0,sizeof(sum));
}
void SPFA(){
    priority_queue<P> qu;
    qu.push(P{2,0});
    dis[2]=0;
    while(!qu.empty()){
        P now=qu.top();
        qu.pop();
        if(vis[now.to]) continue;
        vis[now.to]=1;
        for(int i=0;i<edge[now.to].size();i++){
            P nxt=edge[now.to][i];
            if(dis[nxt.to]>=dis[now.to]+nxt.cost){
                dis[nxt.to]=dis[now.to]+nxt.cost;
                qu.push(P{nxt.to,dis[nxt.to]});
            }
        }
    }
}
int DFS(int now){
    if(now==2) return 1;//到达终点表明有一条路满足
    if(sum[now]) return sum[now];//记忆化搜索剪枝
    for(int i=0;i<edge[now].size();i++)
        if(dis[now]>dis[edge[now][i].to])//谁更近就朝谁走
            sum[now]+=DFS(edge[now][i].to);//当前节点的选择等于所有子节点的选择
    return sum[now];
}
int main()
{
    while(scanf("%d",&n) && n){
        scanf("%d",&m);
        ini();
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&val);
            edge[a].push_back(P{b,val});
            edge[b].push_back(P{a,val});
        }
        SPFA();//其实是Dijkstra
        int ans=DFS(1);
        printf("%d\n",ans);
    }
    return 0;
}

  

posted @ 2019-03-07 14:22  alusang  阅读(331)  评论(0编辑  收藏  举报