天梯赛真题L2-001紧急救援

天梯赛真题L2-001紧急救援

  • 代码
#include<bits/stdc++.h>

using namespace std;
int G[501][501]; //图
int r[501];// 各个城市急救队的人数
int cnt[501]; //最短路径条数
int sr[501]; //当前最小路径时最多的人数
int D[501];//储存最短路径大小
bool f[501];//标记是否已经是最短路径
int p[501];//记录前驱结点
#define INF 0x3f3f3f3f
int n,m,s,d;//城市个数,路的条数,从第s个城市到第d个城市
void Dijkstra();
int main()
{
	cin>>n>>m>>s>>d;//输入
	memset(G,INF,sizeof(G));

	for(int i = 0; i < n; i++)
	{
		cin>>r[i];//输入每个城市救援队的人数
	}
	for(int i = 0; i < m; i++)
	{
		int a,b,c;
		cin>>a>>b>>c;//输入每个边的权值
		G[a][b] = c;
		G[b][a] = c;
	}
	for(int i = 0;i < n; i++)
	{
		G[i][i] = 0;//自己标记为0
	}
	Dijkstra();
	int P[501];
	int D = d;
	int i = 0;
	while(D!=s)
    {
        P[i++] = D;
        D = p[D];
    }
    P[i] = s;
    cout<<cnt[d]<<" "<<sr[d]<<endl;
    for(int j = i; j > 0; j--){
        cout<<P[j]<<" ";
    }
    cout<<d;
	return 0;
}
void Dijkstra()
{
	int mi;
	int u;
	memset(D,INF,sizeof(D));//初始化
	for(int i = 0; i < n; i++)
	{
		D[i] = G[s][i];
		f[i] = false;
		sr[i] = 0;
	}
	sr[s] = r[s];//源点城市的最多派出人数就是该城市的救援人数
	for(int i = 0; i < n; i++)//初始化
	{
	    if(D[i]!=INF&&i!=s) {p[i] = s;sr[i] =r[s] + r[i]; cnt[i] = 1; }//初始化能从源点到达的城市
	    /*前驱结点为源点城市 能派出的最多人数为该城市救援人数加上前驱结点能派出最大人数 最短路径条数为1*/
		else p[i] = -1;
	}
	f[s] = true; cnt[s] = 1;//s为源点 到达s最小值为0 能找到路径只有这一条
	for(int i = 0; i < n-1; i++)
	{
		mi = INF;//标记路径权值最小值
		for(int j = 0; j < n; j++)
		{
			if(!f[j]&&D[j] < mi)//从没找到最小值的城市按个遍历  最小的即为到达该点的最小值
			{
				u = j;
				mi = D[j];
			}
		}
		f[u] = true;// 源点到u的最小路径已找到
		for(int j = 0; j < n; j++)
		{
			if(!f[j]){//更新没找到最小路径的城市
				if(mi+G[u][j] < D[j])//经过u到j小于源点之前到j的路径长度更新
				{
				D[j] = mi + G[u][j];//路径长度更新
				p[j] = u;//j的前驱结点变为u
				sr[j] = r[j]+sr[u];//召集的人数更新
				cnt[j] = cnt[u];//到u的最短路径条数及到j的最短路径条数
				}
				else if(mi+G[u][j]==D[j]){//当此时经过u到达该点路径长度与之前的一样
					cnt[j]+=cnt[u];//路径的条数应该再加上到达u的路径条数
					if(r[j]+sr[u]>sr[j])//只有经过城市u召集的人数大于之前的才更新 前驱结点和此时召集的人数
					{
						sr[j] = r[j]+sr[u];
						p[j] = u;
					}
				}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜康o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值