分析:找到吉米从办公室穿过森林回到家(也就是从点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