L2-001:dijskstra + 多条最短路径 + 记录中间路径

题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805073643683840
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

思路:

题意:找最短路径,如果有多条最短路径值相等,找经过的点最多的一条。
dijkstra算出最短路径,在搜寻最短路时更改一下几点:
1.记录中间路径节点
2.更新最短路时,更新点权和,记录当前节点的最短路数量。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int N=555;
int dis[N];//记录最短距离 
int path[N];//记录最短路径中间节点 
int w[N];
int pathnum[N];//记录最短路径的数目 
int tol[N];//记录总路径的边权之和 
int book[N];
int mp[N][N];//邻接矩阵 
int n,m,s,d;

void print(int x)//递归输出路径
{
	if(path[x]==-1)
	{
		printf("%d",x);
		return ;
	}
	print(path[x]);
	printf(" %d",x);
	return ;
}

void dijkstra()
{
	memset(book,0,sizeof(book));
	memset(tol,0,sizeof(tol));
	int i,j;
	for(i=0;i<n;i++)
		dis[i]=inf;
	dis[s]=0;
	path[s]=-1;
	tol[s]=w[s];//对起始点的初始化
	pathnum[s]=1;//起点的最短路径数为1
	
	for(i=0;i<n;i++)
	{
		int u,minn=inf;
		//找到dis路径权值最小的点u 
		for(j=0;j<n;j++)
		{
			if(!book[j]&&dis[j]<minn)
			{
				u=j;
				minn=dis[j];
			}
		}
		book[u]=1;
		for(j=0;j<n;j++)
		{
			//更新最短路径 以u去更新它的邻接点 
			if(dis[j] > dis[u] + mp[u][j])//松弛时各数组的更新
			{
				dis[j] = dis[u] + mp[u][j];//更新最短路径值 ok 
				path[j] = u;//记录中间路径 ok 
				tol[j] = tol[u] + w[j]; //更新最短路径对应下的顶点最大值 
				pathnum[j] = pathnum[u];//如果dis最短路径的值更新为最大值了 说明是第一次更新,并且是用u去更新的v,所以点j的最短路径数量应该等于u的最短路径数量 
			}
			else if(dis[j] == dis[u] + mp[u][j])//相等时的更新
			{
				pathnum[j] += pathnum[u];//如果最短路径相等了,说明有这两个点的多种方案都可行,应该是二者最短路径的和
				
				//在距离相同时 比较所有的点权和 更新为最大的点权 
				if(tol[j] < tol[u] + w[j])//点权值的更新
				{
					tol[j] = tol[u] + w[j];//更新点权值和
					path[j] = u;//改变中间路径 
				}
			}
		}
	}
}

int main()
{
	int x,y,z;
	scanf("%d%d%d%d",&n,&m,&s,&d);
	for(int i=0;i<n;i++)
		scanf("%d",&w[i]);
	memset(mp,inf,sizeof(mp));
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		mp[x][y]=z;
		mp[y][x]=mp[x][y];
	}
	dijkstra();
	printf("%d %d\n",pathnum[d],tol[d]);
	print(d);
	return 0;
}
posted @ 2019-02-23 11:44  fishers  阅读(932)  评论(0编辑  收藏  举报