Uva10917 Walk Through the Forest
题目链接:https://vjudge.net/problem/UVA-10917
题目意思:Jimmy下班回家要闯过一下森林,劳累一天后在森林中散步是非常惬意的事,所以他打算每天沿着一条不同的路径回家,欣赏不同的风景,但他也不太想太晚回家,因此他不打算走回头路。换句话来说,他只会沿着如下条件的道路(A,B)走:存在一条从B出发回家的路径,比所有从A出发回家的路径都要短。我们的任务是要找出一共有有多少条不同的回家路径,家的编号是2,公司的编号是1。
题目思路:最短路+dp,我们现在考虑如何dp,由于从B回家的路比所有从A回家的路都短,所以如果从2出发跑一遍最短路,如果我们重新建一个图了话,如果原图中存在边,且dist[A]>dist[B]的两个AB之间需要建一条边。现在我们dp,考虑子结构,从x点回家的所有路径是多少?应该是点x的边集中所有dist[y]>dist[x]的点y,回家路径的和。也就说当这些y的回家路径确定了以后x回家的路径的数量才确定。所以我们实际上是跑以2为起点的最短路,以2为起点开始的dfs。直接看代码吧!
代码:
1 //Author: xiaowuga 2 #include <bits/stdc++.h> 3 using namespace std; 4 #define inf 0x3f3f3f3f 5 #define MAX INT_MAX 6 #define mem(s,ch) memset(s,ch,sizeof(s)) 7 const long long N=2000; 8 const long long mod=1e9+7; 9 typedef long long LL; 10 typedef int II; 11 typedef unsigned long long ull; 12 #define nc cout<<"nc"<<endl 13 #define sp " " 14 II n,m; 15 vector<pair<II,II> >G[N]; 16 II d[N]; 17 II path[N],done[N]; 18 void Dijkstra(II s,II t){ 19 II vis[N]; 20 mem(d,inf);mem(vis,0); 21 d[s]=0; 22 priority_queue<pair<II,II> >Q; 23 Q.push(make_pair(-d[s],s));//由于优先队列默认是大顶堆,我们直接放入一个负数就可以了。 24 while(!Q.empty()){ 25 II now=Q.top().second; 26 Q.pop(); 27 if(vis[now]) continue; 28 vis[now]=1; 29 for(II i=0;i<G[now].size();i++){ 30 II v=G[now][i].first,w=G[now][i].second; 31 if(d[v]>d[now]+w){ 32 d[v]=d[now]+w; 33 Q.push(make_pair(-d[v],v)); 34 } 35 } 36 } 37 } 38 II dfs(II u){ 39 if(path[u]!=-1) return path[u]; 40 path[u]=0; 41 for(II i=0;i<G[u].size();i++){ 42 II v=G[u][i].first; 43 if(d[u]<d[v]){ 44 path[u]+=dfs(v); 45 } 46 } 47 return path[u]; 48 } 49 int main() { 50 ios::sync_with_stdio(false);cin.tie(0); 51 while(cin>>n&&n){ 52 cin>>m; 53 for(II i=1;i<=n;i++) G[i].clear(); 54 for(II i=0;i<m;i++){ 55 II a,b,d; 56 cin>>a>>b>>d; 57 G[a].push_back(make_pair(b,d)); 58 G[b].push_back(make_pair(a,d)); 59 } 60 Dijkstra(2,1); 61 //for(II i=1;i<=n;i++) cout<<d[i]<<' '; cout<<endl; 62 mem(path,-1);path[1]=1; 63 II ans=dfs(2); 64 cout<<ans<<endl; 65 } 66 return 0; 67 }