【PAT1003】-Emergency

实现思路

由于是求最短路,我想到了用前向星+SPFA的解法
在求解的过程中注意考虑当两条路的长度相同时,选择累积的消防队最多的那条路
但是提交后:
在这里插入图片描述只通过了第一个测试点

上网找了相关SPFA解法的博客
利用SPFA算法解决PAT A1003

全网最全!PAT甲组1003.Emergency (优先队列实现迪杰斯特拉算法,Bellman算法,SPFA)思路与注意点–补充《算法笔记》

重要警示!!!
不要再脑子不清楚的情况下瞎做题,我一直认为自己的思路没有问题,原来是我没注意题目想要的结果是什么,结果要的不是最短路的长度,而是最短路出现的次数

在SPFA计算相同长度路径出现的次数:
在这里插入图片描述
具体的过程,结合当前的例子来说。
如图所示,设定起点为1,终点为6。
变量的设置:num数组中存储的是起点到达该点的最短路的条数,
——————————————————————————————
从左到右依次可以看到num[3]=1,num[2]=1

能连接到点4的点有1,2,5但其中能满足最短路到点4的路径的点只有3和2
故num[4]=num[2]+num[3]=2

再看能到达7的点的有4和6,且由4和6到达的路径均为最短路
所以num[7]=num[4]+num[6]=3
——————————————————————————————
概括就是统计最短路径到达该点的前一点,累加满足这样条件的前一点的路径数

Bellman实现
如果是使用Folyed-Bellman做法的不需要考虑那么多直接使用的规则是,当最短路更新时,num[v]=num[u],当最短路不变,只不过是通过别的u点到达的
令num[v]=num[v]+num[u]

SPFA实现
如果是SPFA方式的需要辅助一个set集合,当有点到达v的最短路不变时,将新的点放入set集合中再统一进行运算

两种方法在实现的过程中有区别的原因主要是在于:
这样做的原因在于,SPFA运算的过程出了队列的点时有可能再次进入到队列中,而进行Bellman做法时点时不可能再进入到队列中

参考代码(Floyed-Bellman)

#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 99999999;
const int maxn = 505;
int n, m, c1, c2;
int weight[maxn], e[maxn][maxn], w[maxn], num[maxn], dis[maxn];
int visit[maxn];
int main()
{
    
    
	for (int i = 0;i < maxn;i++)
		dis[i] = inf;

	for (int i = 0;i < maxn;i++)
	{
    
    
		for (int j = 0;j < maxn;j++)
			e[i][j] = inf;
	}

	cin >> n >> m >> c1 >> c2;

	for (int i = 0;i < n;i++)
		cin >> weight[i];

	int t1, t2, t3;
	for (int i = 0;i < m;i++)
	{
    
    
		cin >> t1 >> t2 >> t3;
		e[t1][t2] = e[t2][t1] = t3;
	}
	dis[c1] = 0;
	w[c1] = weight[c1];
	num[c1] = 1;

	for (int i = 0;i < n;i++)
	{
    
    
		int k = -1, minn = inf;
		for (int j = 0;j < n;j++)
		{
    
    
			if (!visit[j] && dis[j] < minn)
			{
    
    
				k = j;
				minn = dis[j];
			}
		}
		if (k == -1)
			break;

		visit[k] = 1;

		for (int v = 0;v < n;v++)
		{
    
    
			if (!visit[v] && e[k][v] != inf)
			{
    
    
				if (dis[v] > dis[k] + e[k][v])
				{
    
    
					dis[v] = dis[k] + e[k][v];
					num[v] = num[k];
					w[v] = w[k] + weight[v];
				}
				else if (dis[v] == dis[k] + e[k][v])
				{
    
    
					num[v] = num[k] + num[v];
					if (w[v] < w[k] + weight[v])
					{
    
    
						w[v] = w[k] + weight[v];
					}
				}
			}
		}
	}

	cout << num[c2] << " " << w[c2];

	return 0;
}

参考代码(SPFA)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
 
using namespace std;
 
const int N = 510;
const int INF = 0x3fffffff;
 
struct Node
{
    
    
	int v, dis;
	Node(int _v, int _dis) : v(_v), dis(_dis) {
    
    }
}; 
 
vector<Node> Adj[N];
int n, m, st, ed, weight[N];
int d[N], w[N], num[N];
set<int> pre[N];
 
bool vis[N] = {
    
    false}; 
 
bool SPFA(int s)
{
    
    
	fill(d, d + N, INF);
	memset(vis, false, sizeof(vis));
	memset(num, 0, sizeof(num));
	memset(w, 0, sizeof(w));
	
	queue<int> Q;
	Q.push(s);
	
	vis[s] = true;
	num[s] = 1;
	w[s] = weight[s];
	d[s] = 0;
	
	while(!Q.empty())
	{
    
    
		int u = Q.front();
		Q.pop();
		vis[u] = false;
		
		for(int i = 0; i < Adj[u].size(); i ++)
		{
    
    
			int v = Adj[u][i].v;
			int dis = Adj[u][i].dis;
			
			if(d[u] + dis < d[v])
			{
    
    
				d[v] = d[u] + dis;
				w[v] = w[u] + weight[v];
				num[v] = num[u];
				pre[v].clear();
				pre[v].insert(u);
				if(!vis[v])
				{
    
    
					Q.push(v);
					vis[v] = true;
				}
			}
			else if(d[u] + dis == d[v])
			{
    
    
				if(w[u] + weight[v] > w[v])
				{
    
    
					w[v] = w[u] + weight[v];
				}
				pre[v].insert(u);
				num[v] = 0;
				for(set<int>::iterator it = pre[v].begin(); it != pre[v].end(); it ++)
				{
    
    
					num[v] += num[*it];
				}
				if(!vis[v])
				{
    
    
					Q.push(v);
					vis[v] = true;
				}
			}
		}
	}
	return true;
}
 
 
int main()
{
    
    
//	freopen("test.txt","r",stdin);
	cin >> n >> m >> st >> ed;
	for(int i = 0; i < n; i ++)
	{
    
    
		cin >> weight[i];
	}
	
	int u, v, cost;
	
	for(int i = 0; i < m; i ++)
	{
    
    
		cin >> u >> v >> cost;
		Adj[u].push_back(Node(v, cost));
		Adj[v].push_back(Node(u, cost));
	}
	
	SPFA(st);
	
	cout<<num[ed]<<" "<<w[ed]<<endl;
 
	return 0;
}

总结

要深刻理解不同最短路解法的细微差别,仔细读题不要想当然

猜你喜欢

转载自blog.csdn.net/weixin_44944046/article/details/114371014
今日推荐