分析:找到吉米从办公室穿过森林回到家(也就是从点1到点2)的最短路径有多少条,其中要满足如果要走A到B这条路,那么就有从A到终点的距离都大于B到终点的距离。
解法:spfa算法+记忆化深搜
1、spfa求出从终点2到其他所有点的最短路
2、记忆化DFS从1开始向其他点深搜,最后结果就是dp[1]。
#include<iostream> #include<queue> using namespace std; int u[2000002]; int v[2000002]; int w[2000002]; bool vis[1001]; int d[1001]; int first[1001]; int Next[2000002]; int dp[1001]; void Init(int n,int m) { int i; for(i=1;i<=n;i++) { vis[i]=false; first[i]=-1; dp[i]=-1; } for(i=0;i<m;i++) Next[i]=-1; } int DFS(int u) { int i,sum; if(dp[u]!=-1) return dp[u]; //记忆化 if(u==2) return 1; //终点 sum=0; for(i=first[u];i!=-1;i=Next[i]) { if(d[u]>d[v[i]]) sum+=DFS(v[i]); } return dp[u]=sum; } void spfa(int n,int s) { queue<int> q; int i,x,y; for(i=1;i<=n;i++) d[i]=(i==s)?0:0x7fffffff; //初始化,自己到自己为0,其他到自己相当于无穷大 q.push(s); while(!q.empty()) { x=q.front(); q.pop(); vis[x]=false; for(i=first[x];i!=-1;i=Next[i]) { y=v[i]; if(d[y]>d[x]+w[i]) { d[y]=d[x]+w[i]; if(!vis[y]) { vis[y]=true; q.push(y); } } } } } void Read(int m) { int i,a,b; for(i=0;i<m;i++) { scanf("%d %d %d",&a,&b,&w[i]); u[i]=a; //存储正向边,因为是无向图 v[i]=b; Next[i]=first[a]; first[a]=i; w[i+1]=w[i]; //存储反向边 i++; u[i]=b; v[i]=a; Next[i]=first[b]; first[b]=i; } } int main() { int n,m; while(scanf("%d",&n)==1 && n) { scanf("%d",&m); Init(n,m+m); //m+m是因为无向边,每条都要保存两条 Read(m+m); spfa(n,2); //搜出2到其他所有点的最短路 cout<<DFS(1)<<endl; //从1开始深搜,最终即为结果 } return 0; }
HDU ACM 1142 A Walk Through the Forest->SPFA算法+记忆化深搜
原文地址:http://blog.csdn.net/a809146548/article/details/45315869