PAT---1003 Emergency(迪杰斯特拉算法+求所有最短路)

本篇博文参考了博文:https://blog.csdn.net/m0_37579232/article/details/83039175

先回顾一下一般的迪杰斯特拉算法模板

//循环n-1次,每次有一个节点加入
for(int i = 0; i < n-1; i++)
{
		//松弛操作,更新与新加入的结点newp直接相邻的结点的dist
		for(int j = 0; j < edge[newp].size(); j++)
		{
			int t = edge[newp][j].next;
			int c = edge[newp][j].weight;
			//如果已经加入,则跳过
			if(mark[t])
				continue;
			if(dist[t] == -1 || dist[newp] + c < dist[t])
				dist[t] = dist[newp] + c;
		}

		//找到未加入最短路径集合的距离v0最短的结点
		int min = 111111111;
		for(int j = 0; j < n; j++)
		{
			if(mark[j])
				continue;
			if(dist[j] == -1)
				continue;
			if(dist[j] < min)
			{
				min = dist[j];
				newp = j;
			}
		}
        mark[newp] = true;    //新加入的结点
}

dist数组的含义是从source到current的最短路径,我们可以类比dist数组,设置另外两个数组,count数组和tot数组,分别表示从source到current的最大求援人数和最短路径的个数。
从上面的松弛操作可以看出,对于一般的迪杰斯特拉算法,每个结点只计算了一次,因此为了计算从source到current的所有最短路径和最大救援人数,将松弛操作中的if(mark[])语句删除即可。因此变形后的松弛操作就是:

            //更新与新加入的结点newp直接相邻的结点的dist
			for(int j = 0; j < edge[newp].size(); j++)
			{
				int t = edge[newp][j].next;
				int c = edge[newp][j].weight;

				//如果dist[t] == dist[newp]+c说明有多条路径
				if(dist[t] == dist[newp] + c)
				{
					tot[t] += tot[newp];   //多条路径
					if(count[t] < count[newp] + num[t])
						count[t] = count[newp] + num[t];
				}
				if(dist[t] == -1 || dist[newp] + c < dist[t])
				{
					dist[t] = dist[newp] + c;
					count[t] = count[newp] + num[t];
					tot[t] = tot[newp];
				}
			}
//AC代码
#include <iostream>
#include <vector>

using namespace std;

typedef struct Node
{
	int next, weight;
};

vector<Node> edge[501];    //邻接链表
bool mark[501];
int dist[501];
int num[501];       //用于记录各个city的目前的救援人数
int count[501];    //用于保存到各个city的最多参加救援的人数
int tot[501];      //用于保存到各个city的路径个数

int main()
{
	int n, m, c1, c2;
	int x, y, z;
	while(cin >> n >> m >> c1 >> c2)
	{
		//初始化邻接链表
		for(int i = 0; i < n; i++)
			edge[i].clear();

		for(int i = 0; i < n; i++)
			cin >> num[i];
		Node tmp;
		for(int i = 0; i < m; i++)
		{
			cin >> x >> y >> z;
			tmp.next = y, tmp.weight = z;
			edge[x].push_back(tmp);
			tmp.next = x;
			edge[y].push_back(tmp);
		}

		//初始化
		for(int i = 0; i < n; i++)
		{
			mark[i] = false;
			dist[i] = -1;
			count[i] = num[i];
			tot[i] = 0;
		}

		dist[c1] = 0;
		mark[c1] = true;
		int newp = c1;
		tot[c1] = 1;      //肯定至少有一条从c1到c2的最短路径
		//循环n-1次,每循环一次,加入一个结点到最短路径集合
		for(int i = 0; i < n-1; i++)
		{
			//更新与新加入的结点newp直接相邻的结点的dist
			for(int j = 0; j < edge[newp].size(); j++)
			{
				int t = edge[newp][j].next;
				int c = edge[newp][j].weight;

				//如果dist[t] == dist[newp]+c说明有多条路径
				if(dist[t] == dist[newp] + c)
				{
					tot[t] += tot[newp];   //多条路径
					if(count[t] < count[newp] + num[t])
						count[t] = count[newp] + num[t];
				}
				if(dist[t] == -1 || dist[newp] + c < dist[t])
				{
					dist[t] = dist[newp] + c;
					count[t] = count[newp] + num[t];
					tot[t] = tot[newp];
				}
			}

			//找到未加入最短路径集合的距离v0最短的结点
			int min = 111111111;
			for(int j = 0; j < n; j++)
			{
				if(mark[j])
					continue;
				if(dist[j] == -1)
					continue;
				if(dist[j] < min)
				{
					min = dist[j];
					newp = j;
				}
			}
            mark[newp] = true;
		}

		printf("%d %d\n", tot[c2], count[c2]);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值