PTA甲级考试真题练习3——1003 Emergency

  • 题目:
    在这里插入图片描述
  • 思路:
    该题就是求图的最短路径,首先注意求得是最短路径的数目而不是最短路径的长度,然后还有一个救援队的问题。下面使用两种方法解决该问题:

(1)dijkstra算法:
基本思想:每次找到离源点(如1号节点)最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。

  • 基本步骤:
    1,设置标记数组book[]:将所有的顶点分为两部分,已知最短路径的顶点集合P和未知最短路径的顶点集合Q,很显然最开始集合P只有源点一个顶点。book[i]为1表示在集合P中;
    2,设置最短路径数组dst[]并不断更新:初始状态下,dst[i]=edge[s]i,很显然此时dst[s]=0,book[s]=1.此时,在集合Q中可选择一个离源点s最近的顶点u加入到P中。并依据以u为新的中心点,对每一条边进行松弛操作(松弛是指由顶点s–>j的途中可以经过点u,并令dst[j]=min(dst[j],dst[u]+edge[u][j])),并令book[u]=1;
    3,在集合Q中再次选择一个离源点s最近的顶点v加入到P中。并依据v为新的中心点,对每一条边进行松弛操作(即dst[j]=min(dst[j],dst[v]+edge[v][j])),并令book[v]=1;
    4,重复3,直至集合Q为空。
  • 代码:
#include <iostream>
#include <cstring>
#define nmax 1000
#define inf 999999
using namespace std;
int minpath[nmax],maxperson[nmax], n, m, edge[nmax][nmax],book[nmax],person[nmax];   //最短路径,节点数,边数,终点,邻接矩阵,集合标记,
int src, dest;   //源和目的
int ipath[nmax];

void Dijkstra()
{
	//找除了源点外的n-1个点
	for (int i = 0; i < n; i++)
	{
		int min = inf;
		int u = 0;
		for (int j = 0; j < n; j++)
		{
			if (book[j] == 0 && minpath[j] < min)
			{
				min = minpath[j];
				u = j;
			}
		}
		book[u] = 1;
		//更新最短距离
		for (int j = 0; j < n; j++)
		{
			if (book[j] == 0 && minpath[u] + edge[u][j] < minpath[j])
			{
				minpath[j] = minpath[u] + edge[u][j];
				ipath[j] = ipath[u];
				maxperson[j] = maxperson[u] + person[j];
			}
			else if (book[j] == 0 && minpath[u] + edge[u][j] == minpath[j])
			{
				ipath[j] += ipath[u];
				if (maxperson[j] < maxperson[u] + person[j])
					maxperson[j] = maxperson[u] + person[j];
			}
		}
	}
}
int main()
{
	int a, b;
	int count = 0;
	cin >> n >> m >> src >> dest;
	for (int i = 0; i < n; i++)
	{
		cin >> person[i];
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			edge[i][j] = inf;
		}
	}
	for (int i = 0; i < m; i++)
	{
		cin >> a >> b;
		cin >> edge[a][b];
		edge[b][a] = edge[a][b];
	}
	memset(book, 0, sizeof(book));
	for (int i = 0; i < n; i++)
	{
		ipath[i] = 1;
		minpath[i] = edge[src][i];
		if(minpath[i]!=inf&&i!=src)
			maxperson[i] = person[src] + person[i];
	}	
	minpath[src] = 0;
	maxperson[src] = person[src];
	book[src] = 1;
	Dijkstra();
	cout << ipath[dest] <<" "<<maxperson[dest];
	return 0;
}

(2)深度或广度优先算法:
从起点开始访问所有深度遍历路径或广度优先路径,则到达终点节点的路径有多条,取其中路径权值最短的一条则为最短路径。
和上面dijkstra相比较功能捡漏但是更加容易实现

#include <iostream>
#include <cstring>
#define nmax 1000
#define inf 999999
using namespace std;
int minpath = inf, maxperson = 0, n, m, edge[nmax][nmax], mark[nmax], person[nmax];   //最短路径,节点数,边数,终点,邻接矩阵,节点访问标记
int src, dest;   //源和目的
int path = 1;

void dfs(int cur, int dst, int num)
{
	if (dst > minpath) return;   //如果距离已经大于最小路径了直接返回
	if (cur == dest) {  //如果到达目的地
		if (dst < minpath) {
			minpath = dst;
			maxperson = num;
			path = 1;
		}
		else if (dst == minpath) {
			if(num > maxperson)
				maxperson = num;
			path += 1;
		}
		return;
	}
	for (int i = 0; i < n; i++)
	{
		if (edge[cur][i] != inf && edge[cur][i] != 0 && mark[i] == 0)
		{
			mark[i] = 1;
			dfs(i, dst + edge[cur][i], num + person[i]);
			mark[i] = 0; //递归返回要将mark置0
		}
	}
}
int main()
{
	int a, b;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			edge[i][j] = inf;
		}
		edge[i][i] = 0;
	}
	cin >> n >> m >> src >> dest;
	for (int i = 0; i < n; i++)
	{
		cin >> person[i];
	}
	for (int i = 0; i < m; i++)
	{
		cin >> a >> b;
		cin >> edge[a][b];
		edge[b][a] = edge[a][b];
	}
	memset(mark, 0, sizeof(mark));
	mark[src] = 1;
	dfs(src, 0, person[src]);
	cout << path << " " << maxperson;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值