题目大意:对于图中节点要从起点走向终点,而且能从A节点走向B节点的条件是在B点存在一条到终点的路径,且这条路径的长度小于任何从A节点通往终点路径的长度,求共有几种走法。
对于图中限制条件,其实只要判断从B到终点的最短路径是否小于从A点到终点的最小距离,若小于,则可以,否则不可以。
经过这样转化后,题目将十分明显,深搜即可,但发现图中节点十分多,最多能达到1000个,所以深搜过程中要用记忆化搜索。
#include <stdio.h>
#include <string.h>
#define INF 2000000
int map[1010][1010],n,m;
int low[1010],s[1010];//low存放最短路径,s为标志数组,看某节点的最短路径是否求出
int cap[1010];//记忆化搜索用到的,cap[i]记录从节点i到终点的走法数目
int dfs(int i)//记忆化搜索
{
int j;
if(i==2)
return 1;
if(cap[i]!=0)
return cap[i];
for(j=1;j<=n;j++)
if(i!=j&&map[i][j]<INF&&low[j]<low[i])//限制条件
cap[i]+=dfs(j);
return cap[i];
}
int main()
{
int i,j,k;
int x,y,w;
int ans,min,u;
while(1)
{
memset(cap,0,sizeof(cap));
memset(s,0,sizeof(s));
scanf("%d",&n);
if(n==0)
break;
scanf("%d",&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=INF;
}
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&w);
map[y][x]=map[x][y]=w;
}
for(i=1;i<=n;i++)//用的是dijkstra算法
low[i]=map[2][i];
s[2]=1;
for(i=1;i<n;i++)
{
min=INF;
for(j=2;j<=n;j++)
{
if(s[j]==0&&low[j]<min)
{
min=low[j];
u=j;
}
}
s[u]=1;
for(j=1;j<=n;j++)
{
if(s[j]==0&&low[j]>low[u]+map[u][j]&&map[j][u]<INF)
low[j]=low[u]+map[u][j];
}
}
ans=dfs(1);
printf("%d\n",ans);
}
return 0;
}