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;
}

  

转载于:https://www.cnblogs.com/JustDoA/p/10489388.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值