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