题目:http://acm.scs.bupt.cn/onlinejudge/showproblem.php?problem_id=1095
题意:这题要在一个无向正权图上找单源最短路,找到目标点后,还要求出到达这个点的最短路径的数量。有重边。
解法:dijkstra+DP。正权图找最短路首先想到dijkstra,然后考虑如何获得最短路数量和怎样处理重边。因为两点间只需一条最的路径就够了,因此记录图的时候可以考虑忽略其他权比较高的路径,只记录最短的那条。并且增加一个二元数组记录相邻点间的最短路径条数。此外有数组d记录起点到各点的最短距离,count记录到达这点的最短路径数。在dijkstra过程中,加入新节点后松弛没找到最短路的点的过程中,考虑如果松弛过程中d[i]==d[pos]+map[pos][i],则count[i]+=count[pos]*p[pos][i](此处之前错误写成了count[i]++,-_-!),如果d[i]>d[pos]+map[pos][i],则count[i]=count[pos]*p[pos][i]。最后输出d[b],count[b]就行,注意各数组初始化,并且注意是两组输出之间有空行,最后一组输出后不用空行,仅换行,这里我也悲剧了一次。
code:
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
int main()
{
long cur,pos,temp;
long f,m,n,i,j,x,y,l,a,b;
long map[310][310],p[310][310],count[310],d[310],flag[310];
scanf("%ld",&f);
while(f--)
{
scanf("%ld%ld",&n,&m);
memset(map,0,sizeof(long)*310*310);
for(i=0;i<m;i++)
{
scanf("%ld%ld%ld",&x,&y,&l);
if(map[x][y]&&map[x][y]==l)
{
p[x][y]++;
p[y][x]++;
}
else if(map[x][y]&&map[x][y]>l)
{
map[x][y]=l;
map[y][x]=l;
p[x][y]=1;
p[y][x]=1;
}
else if(!map[x][y])
{
map[x][y]=l;
map[y][x]=l;
p[x][y]=1;
p[y][x]=1;
}
}
scanf("%ld%ld",&a,&b);
for(i=0;i<=n;i++)
{
flag[i]=0;
d[i]=1000000000;
}
d[a]=0;
flag[a]=1;
cur=a;
count[a]=1;
for(i=1;i<=n;i++)
{
if(map[a][i])
{
d[i]=map[a][i];
count[i]=count[a]*p[a][i];
}
}
while(!flag[b])
{
temp=1000000000;
pos=-1;
for(i=1;i<=n;i++)
{
if(!flag[i]&&d[i]&&d[i]<temp)
{
temp=d[i];
pos=i;
}
}
if(pos==-1)
break;
flag[pos]=1;
for(i=1;i<=n;i++)
{
if(!flag[i]&&i!=pos&&map[pos][i]&&d[i]==d[pos]+map[pos][i])
{
count[i]+=count[pos]*p[pos][i];
}
else if(!flag[i]&&i!=pos&&map[pos][i]&&d[i]>d[pos]+map[pos][i])
{
d[i]=d[pos]+map[pos][i];
count[i]=count[pos]*p[pos][i];
}
}
}
if(flag[b])
{
printf("%ld %ldn",d[b],count[b]);
}
else
{
printf("Poor Javamann");
}
if(f!=0)
printf("n");
}
}




Leave a Reply