基础实验6-2.5 城市间紧急救援 (25 分)

要准备的数组:

G[][] 图用邻接矩阵存储,初始化为无穷大,自己到自己初始化为0;dist[] 存储顶点到source的距离,初始化为无穷大;pre[]存储顶点的前驱结点用来输出路径用,初始化为-1

vis[]用来表示顶点已被收录到集合S中,初始化为false;num[]用来存储最短路径的条数,初始化为0;Weight[]存每个点救援队的数目,即点权,直接读入题目给的数据即可,无须初始化;

W[]用来存储source到顶点这条路径上救援队的总数量,初始化为0

本题基本思路就是Dijkstra算法,只不过这个题增加了点权,并且要记录最短路径的长度。因此在dist[]相同的时候要看一下救援队数量会不会增加。如果会增加就要更新救援队的数量W[], 前驱数组pre[], 最短路径的条数num[]。如果救援队的数量不增加,记得也要更新最短路径的条数!(在这里犯过错误导致测试点1没通过)。

Dijkstra算法进入后先要对源点的相关数据进行初始化:dist[S] = 0; pre[S] = -1; num[S] = 1(因为自己到自己只有一条路,陈姥姥mooc上教的);W[S] = Weight[S]; 注意:不要初始化vis[S]为true,因为后面的第一次循环会处理S。

初始化完成后就可以进入常规的Dijkstra操作了。先找未被收录的最小的dist[],然后把它收录到集合S中,再检查一下收录到S后会不会影响它的一圈邻接点,如果会的话进行相应的更新即可。

下面是这个题的代码:

#include<stdio.h>
#include<stack>
#define INF 10000000
using namespace std;
#define MAXV 505
int n, G[MAXV][MAXV];
int dist[MAXV];
int pre[MAXV];
bool vis[MAXV] = {false};
int num[MAXV];//路径的数目
int Weight[MAXV];//点权
int W[MAXV];//从原点到某个顶点的城市救援队的数目
void Dijkstra(int S)
{
	int i,j,k,z;
	int MinDist,MinV;
	/*对数据进行必要的基础准备*/
	dist[S] = 0;
	pre[S] = -1;
	num[S] = 1;
	W[S] = Weight[S];
	/*下面正式进入Dijkstra*/
	for(i=0; i<n; i++)
	{
		MinDist = INF; MinV = -1;
		for(j=0; j<n; j++)//找到未被访问过的dist[]
		{
			if(vis[j]==false&&dist[j]<MinDist)
			{
				MinDist = dist[j];
				MinV = j;
			}
		}
		if(MinV == -1) return;
		/*没有退出循环说明找到了,继续执行后面的步骤*/
		vis[MinV] = true;
		for(k=0; k<n; k++)
		{
			if(G[MinV][k]<INF&&vis[k]==false)
			{
				if(dist[MinV]+G[MinV][k] < dist[k])
				{
					dist[k] = dist[MinV] + G[MinV][k];
					pre[k] = MinV;
					num[k] = num[MinV];
					W[k] = W[MinV] + Weight[k];
				}
				else if((dist[MinV]+G[MinV][k]==dist[k])&&(W[MinV]+Weight[k]>W[k]))
				{
					pre[k] = MinV;
					num[k] = num[MinV] + num[k];
					W[k] = W[MinV] + Weight[k];
				}
				else if(dist[MinV]+G[MinV][k]==dist[k])
					num[k] = num[MinV] + num[k];
			}
		}
	}
}
int main()
{
	int N,M,S,D;
	int i,j;
	scanf("%d %d %d %d",&N,&M,&S,&D);
	for(i=0; i<N; i++)
	{
		scanf("%d",&Weight[i]);
	}
	int V1,V2,L;
	/*初始化*/
	n = N;
	for(i=0; i<n; i++)
		for(j=0; j<n; j++)
		{
			G[i][j] = INF;
		}
	/*初始化*/	
	for(i=0; i<M; i++)
	{
		scanf("%d %d %d",&V1,&V2,&L);
		G[V1][V2] = L;
		G[V2][V1] = L;
	}
	for(i=0; i<n; i++)
	{
		pre[i] = -1;
		num[i] = 0;
		dist[i] = INF;
		W[i] = 0;
		G[i][i] = 0;
	}
	/*初始化*/
	Dijkstra(S);
	stack<int> q; int path;
	printf("%d %d\n",num[D],W[D]);
	while(D!=-1)
	{
		q.push(D);
		D = pre[D];
	}
	int count = q.size();
	for(i=0; i<count-1; i++)
	{
		path = q.top(); q.pop();
		printf("%d ",path);
	}
	printf("%d",q.top());
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值