提交情况:
#include <iostream>
#include <string.h>
using namespace std;
#define Max 510
#define INF 0x3f3f3f3f
//Graph为邻接矩阵存储图,weight为点权,w记录最短路径上的点权之和
int Graph[Max][Max],weight[Max],w[Max];
//visit为访问数组,为0代表未被访问
//dist记录最短的路径;num代表最短的路径的条数,初始时都为0
int visit[Max],dist[Max],num[Max];
int n,m,c1,c2;
void Dijkstra( int start )
{
visit[start] = 1;
for( int i=0;i<n;++i )
{
int vertex = -1,min = INF;
for( int j=0;j<n;++j) //找到距离最短的节点
{
if( visit[j] == 0 && dist[j] < min )
{
vertex = j;
min = dist[j];
}
}
visit[vertex] = 1; //vertex为中介节点,通过vertex检查其它的节点
for( int j=0;j<n;++j ) //用找到的节点检查其它节点.其中j为需要检查的节点
{
if( visit[j] == 0 && dist[vertex]+Graph[vertex][j] < dist[j] ) //找到某一条更短的路径
{ //则更新最短路径长度和点权之和
dist[j] = dist[vertex]+Graph[vertex][j]; //只要找到最短的路径就要更新点权,因为路径优先
w[j] = w[vertex] + weight[j];
num[j] = num[vertex]; //找到新的最短路径,则数量设置为1.
//我也不知道为什么这样写,我看的别人的代码
}
else if( visit[j] == 0 && dist[vertex]+Graph[vertex][j] == dist[j] ) //如果有相同的最短路径
{ //则更新条数和点权
num[j] = num[vertex]+num[j]; //我也不知道为什么这么写,我还是看的别人的代码。其余的代码都是我自己写的
if( w[vertex] + weight[j] > w[j] ) //如果中介节点的点权与检查节点的点权之和大于目前已知的最短路径上的点权
{
w[j] = w[vertex] + weight[j];
}
}
}
}
}
int main()
{
cin>>n>>m>>c1>>c2;
for(int i=0;i<n;++i)
{
cin>>weight[i];
memset(Graph[i],INF,sizeof(Graph[i]));
}
for(int i=0;i<m;++i)
{
int a,b,length;
cin>>a>>b>>length;
Graph[a][b] = length;
Graph[b][a] = length;
}
//初始化操作
for( int i=0;i<n;++i )
{
dist[i] = Graph[c1][i]; //初始化dist数组,一开始dist数组的值对应邻接矩阵中从c1中那一行的值
if( Graph[c1][i] != INF ) //如果直接有边与c1相接,则把w[i]设置为起始节点和和相接的节点的点权之和
{ //因为有边相接,所以存在目前已知的最短路径,因此把num[i]设置为1
w[i] = weight[c1] + weight[i]; //初始化w数组
num[i] = 1;
}
}
w[c1] = weight[c1];
num[c2] = 1;
memset(visit,0,sizeof(visit));
Dijkstra(c1);
cout<<num[c2]<<" "<<w[c2];
return 0;
}
一开始我写的代码只有部分正确,只能得13分,后来加上对c1==c2(即起始节点和结束节点相同)的判断之后也只能得16分。后来怎么想也不明白哪里没有考虑到。偶尔一眼看到《算法笔记》 上的两句代码,收到启发,才知道自己错在哪里。
主要改了两处代码:
1、num[j] = 1;改为num[j] = num[vertex];、
这处改动是当检测到有更短的路径长度时,更新num[j]。num[j] = 1只是简单地讲num[j]设置为1。这样没有考虑到到达中介节点的路径条数,即:从开始节点到达vertex节点的路径条数。
当通过中介节点3进行检测时,发现通过中介节点3到达节点5的路径长度为4,比路径0-1-5长度少。此时num[3] = 2;num[5] = 1;若简单地将num[5]置为1,并符合实际情况,而应该设置为到达中介节点的路径长度,即num[5] = num[3] =2;
2、++num[j];改为num[j] = num[vertex]+num[j];
这处改动是当检测到相同的路径长度时,将num[j]进行加1操作。同样这样做并没有考虑到以前的路径的情况,即改动之后等式有边的num[j];和到达中介节点的路径条数。如下图所示:
当起始节点为0,通过中介节点3到达节点5时,与0-1-5的路径长度相同。此时num[3] = 2,num[5] = 1(即0-1-5这一条路径)。不应该简单将num[j]加1。而是num[j] = num[vertex]+num[j]=2+1=3。就是这种情况,不知道我理解的对吗?我举得例子形象生动吗?画的图清楚吗?好心累