链接:http://poj.org/problem?id=3463
题意:给定一个图和起点S、终点F,求最短路的数量和比最短路大1的路径的数量。
题解:建立二维dijk数组,分别为最短路和次短路,若最短路比次短路小1,则输出它们的数量。
dis[0][i]描述最短路径,dis[1][i]描述次短路径的长度,way[0][i],way[1][i]分别描述最短路、次短路的数量。
check[0][i]\check[1][i]为标号。
由于采用dijk思想,所以每次从堆里出来的必定是最短路,或者是次短路(当最短路已出来时)。
1、每次从没有被标记过的dis[][]中选出最小值,记录该点v
2、更新与v点相连的点的dis值和way值。
3、2n-1个循环(每一个循环算出一个dis[][]值)
4、有重边,用邻接表。
#include<stdio.h>
#include<string.h>
#define M 1000000
int dis[2][1200],way[2][1200],check[2][1200];
int adj[1200];
int n,m;
struct aa
{
int to,w,next;
}map[10020];
void dijk(int s)
{
int i,j;
int u,v,min;
int k,w,c;
memset(check,0,sizeof(check));
memset(way,0,sizeof(way));
for(i=0;i<=1;i++)
for(j=1;j<=n;j++)
dis[i][j]=M;
dis[0][s]=0;way[0][s]=1;
for(i=1;i<2*n;i++)
{
for(j=1,min=M;j<=n;j++) //从dis[][]中找出权值最小且未被走过的一个,走该路径
{
if(check[0][j]==0&&dis[0][j]<min)
{
u=0;v=j;
min=dis[0][j];
}
if(check[1][j]==0&&dis[1][j]<min)
{
u=1;v=j;
min=dis[1][j];
}
}
check[u][v]=1;
//找出该点v后,更新与它相邻的点的dis值
//if 比dis[0][v]小,则最小为次小,该值为最小,更新最短和次短的way
//else if 与dis[0][v]相等,则way+
//else if 小于dis[1][v],则该值为次短,更新way
//else if 等于dis[1][v],way+
for(j=adj[v];j!=-1;j=map[j].next)
{
k=map[j].to;w=map[j].w;
c=dis[u][v]+w;
if(c<dis[0][k])
{
dis[1][k]=dis[0][k];
way[1][k]=way[0][k];
dis[0][k]=c;
way[0][k]=way[u][v];
}
else
if(c==dis[0][k])
way[0][k]+=way[u][v];
else
if(c<dis[1][k])
{
dis[1][k]=c;
way[1][k]=way[u][v];
}
else
if(c==dis[1][k])
way[1][k]+=way[u][v];
}
}
}
int main()
{
int i,j,t;
int a,b,c;
int s,e;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(adj,-1,sizeof(adj));
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[i].to=b;map[i].w=c;map[i].next=adj[a];adj[a]=i;
}
scanf("%d%d",&s,&e);
dijk(s);
if(dis[1][e]==dis[0][e]+1)
way[0][e]+=way[1][e];
printf("%d\n",way[0][e]);
}
}