题意:
现有一个加权无向连通图。给你一个正整数 n ,表示图中有 n 个节点,并按从 1 到 n 给节点编号;
另给你一个数组 edges ,其中每个 edges[i] = [ui, vi, weighti] 表示存在一条位于节点 ui 和 vi 之间的边,
这条边的权重为 weighti 。
从节点 start 出发到节点 end 的路径是一个形如 [z0, z1, z2, ..., zk] 的节点序列,
满足 z0 = start 、zk = end 且在所有符合 0 <= i <= k-1 的节点 zi 和 zi+1 之间存在一条边。
路径的距离定义为这条路径上所有边的权重总和。
用 distanceToLastNode(x) 表示节点 n 和 x 之间路径的最短距离。
受限路径 为满足 distanceToLastNode(zi) > distanceToLastNode(zi+1) 的一条路径,
其中 0 <= i <= k-1 。
返回从节点 1 出发到节点 n 的 受限路径数 。由于数字可能很大,请返回对 1e9 + 7 取余 的结果。
数据范围:
1 <= n <= 2 * 1e4
n - 1 <= edges.length <= 4 * 1e4
edges[i].length == 3
1 <= ui, vi <= n
ui != vi
1 <= weighti <= 1e5
任意两个节点之间至多存在一条边
任意两个节点之间至少存在一条路径
解法:
首先显然要计算出点n到其他点的最短路,设点n到点i的最短路为dist[i].
接下来就是计算点1到点n的受限路径数量,
设d[i]表示点i到点n的受限路径数量,
d[x]=sum(d[v]),其中x与v之间有边,且dist[x]>dist[v],
dp一下就行了,用dfs记忆化搜索.
code:
#define PI pair<int,int>
#define ll long long
const int maxm=1e5+5;
const int mod=1e9+7;
vector<PI>g[maxm];
int mark[maxm];
ll dist[maxm];
int d[maxm];
int n;
class Solution {
public:
void dj(){
priority_queue<PI,vector<PI>,greater<PI> >q;
for(int i=1;i<=n;i++)dist[i]=1e18,mark[i]=0;
dist[n]=0;
q.push({dist[n],n});
while(q.size()){
int x=q.top().second;q.pop();
if(mark[x])continue;
mark[x]=1;
for(auto i:g[x]){
int v=i.first,w=i.second;
if(dist[v]>dist[x]+w){
dist[v]=dist[x]+w;
q.push({dist[v],v});
}
}
}
}
void dfs(int x){
if(d[x]!=-1)return ;
if(x==n){
d[x]=1;
return ;
}
d[x]=0;
for(auto [v,vv]:g[x]){
if(dist[v]<dist[x]){
dfs(v);
d[x]=(d[x]+d[v])%mod;
}
}
}
int countRestrictedPaths(int nn, vector<vector<int>>& e) {
n=nn;
for(int i=1;i<=n;i++)g[i].clear();
for(auto i:e){
int x=i[0],y=i[1],z=i[2];
g[x].push_back({y,z});
g[y].push_back({x,z});
}
dj();
for(int i=1;i<=n;i++)d[i]=-1;
dfs(1);
return d[1];
}
};