题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805073643683840

一道迪杰斯特拉的变形题,之前我这个弱鸡基本只做了模板或接近模板的题。这道题可以很好的帮助我消化最短路径。
在看了一遍题解后自己有敲了一遍,结果还是出现了一些错误,大部分都是比较小的错误。做错过的地方已经注释了

需要求出  最短路径的数量 和 最多召集救援人员的数量与路径

难点是需求的地方比较多,而且救援人员那里刚开始没有读明白。

召集人员数量和最短路径数量都可以通过递推方式来实现

思路:

用way数组记录到达某一点的不同的方式,当前点到达的数量=它已经记录的数量+它前驱的数量(前驱可能改变)

用father数组记录某一个点的前驱

用sumpeple记录调走的人员(当存在多条路径时,人员调走多的更新father,人员调走少的只记录way)

用find函数找回路径。


#include<bits/stdc++.h>
using namespace std;
#define ll long long
int mapt[510][510];
int father[510];
int way[510]; 
int people[510];
int sum_people[510];
bool vis[510];
int dis[510];
int n,m,s,t;
void find(int a)
{
	if(a==s)//和目的地做对比而不是终点 
	{
		cout<<s; 
		return; 
	}else{
		find(father[a]);
	}
	cout<<' '<<a;
}
void djs()
{
	int i,j;
	for(i=0;i<n;i++)
	{
		int m_len = 0x3f3f3f3f,index = i;
		for(j=0;j<n;j++)
		{
			if(m_len>dis[j]&&!vis[j])//   m_len>dis[i]&&!vis[j]
			{
				m_len = dis[j];
				index = j;
			}
		}
		vis[index]=true;
		
		for(j=0;j<n;j++)
		{
			if(!vis[j]&&dis[j]>dis[index]+mapt[index][j])
			{
				dis[j]=dis[index]+mapt[index][j];
				sum_people[j]=sum_people[index]+people[j];
				vis[j]=false;
				way[j]=way[index];
				father[j]=index;
			}else if(!vis[j]&&dis[j]==dis[index]+mapt[index][j])
			{
				if(sum_people[j]<sum_people[index]+people[j])//用现在召集的+这个点的 
				{
					sum_people[j]=sum_people[index]+people[j];
					father[j]=index;
				}
				way[j]+=way[index];
			}
		}
	}
}
int main()
{
	memset(mapt,0x3f,sizeof mapt);
	int i,a,b,c;
	cin>>n>>m>>s>>t;
	for(i=0;i<n;i++)//这里注意是 0 -  n 
		cin>>people[i];
	for(i=1;i<=m;i++)
	{
		cin>>a>>b>>c;
		mapt[a][b]=c;
		mapt[b][a]=c;
	}
	for(i=0;i<n;i++)
	{
		dis[i]=mapt[s][i];
	} 
	dis[s]=0;
	way[s]=1;
	sum_people[s]=people[s];//人数初始 
	djs();
	cout<<way[t]<<' '<<sum_people[t]<<endl;
	find(t);
	return 0; 
}