再看patA1003:SPFA+DFS实现法
之前使用的是dijkstra算法,今天学习了BF和SPFA,故换个方法实现。
首先在SPFA算法处要注意:每次进行松弛边操作后,若松弛后更优,就要将边的另一个节点加入队列(先判断该节点是否已在队列中),并修改disTo数组和pathTo数组;若松弛后与松弛前的disTo值相等,则只补充pathTo数组。而这里是不能使用vector数组实现pathTo数组的,因为BF中可能会多次松弛一个节点,而如果另pathTo的每个元素都是一个vector容器,则会出现里面有重复值的情况,所以这里需要改用std::set容器。
至于通过DFS计算标尺的值,这个与上一篇文章的处理大同小异,只要注意正确的将路径最后一个元素pop_back即可。
代码如下:
#include<iostream>
#include<queue>
#include<vector>
#include<set>
#include<cstdio>
#include<cstring>
using namespace std;
//用于邻接表
struct edge {
	int id;
	int dist;
	edge(int _id,int _dist):id(_id),dist(_dist){}
};
//存节点的救援组数量
struct node {
	int id;
	int resc;
	node(int _id,int _resc):id(_id),resc(_resc){}
};
const int MAX = 500;
const int INF = 0x3fffffff;
//节点数、边数、源点、汇点
int N, M, S, D;
//邻接表
vector<edge> adj[MAX];
//每个点的救援组
int resc[MAX] = { 0 };
//disTo数组
int disto[MAX];
//pathTo数组
set<int> pathto[MAX];
//判别节点是否在队列中
int inq[MAX] = { false };
//结果
int pathnum = 0, rescnum = 0;
//储存一条最短路径
vector<int> temppath;
void input() {
	cin >> N>>M>>S>> D;
	for (int i = 0; i < N; i++)
		cin >> resc[i];
	for (int i = 0; i < M; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		adj[u].push_back(edge(v,w));
		adj[v].push_back(edge(u, w));
	}
}
//求解最短路径,填充disTo,pathTo
void SPFA() {
	//初始化
	fill(disto, disto + MAX, INF);
	disto[S] = 0;
	//创建队列并将源点加入
	queue<int> q;
	q.push(S);
	//while 队列非空
	while (!q.empty()) {
		//出队一个节点
		int u = q.front();
		q.pop();
		inq[u] = false;
		//松弛该节点,将被松弛的另一端节点加入队列
		for (int i = 0; i < adj[u].size(); i++) {
			int v = adj[u][i].id;
			int dist = adj[u][i].dist;
			if (disto[v] > dist + disto[u]) {
				//松弛边,修改pathto
				disto[v] = dist + disto[u];	
				pathto[v].clear();
				pathto[v].insert(u);
				if (!inq[v]) {
					q.push(v);
					inq[v] = true;
				}					
			}
			else if (disto[v] == dist + disto[u]) {
				//修改pathto
				pathto[v].insert(u);
			}
		}
	}	
}
//计算temppath对应的总救援组数量
int cal() {
	int sum=0;
	for (int i = 0; i < temppath.size(); i++) {
		int u = temppath[i];
		sum += resc[u];
	}
	return sum;
}
//使用DFS计算最短路径数,最大点权值
void DFS(int id) {
	//当前节点是源点
	if (id == S) {
		temppath.push_back(id);
		//计算rescnum
		int sum = cal();
		if (sum > rescnum)	rescnum = sum;
		//更新pathnum
		pathnum++;
		//删除最后一个元素
		temppath.pop_back();
	}
	//当前节点不是源点
	else {
		temppath.push_back(id);
		for (auto iter=pathto[id].begin();iter!=pathto[id].end();iter++) {
			int v = (*iter);
			DFS(v);
		}
		temppath.pop_back();	//记得删除最后一个元素
	}
}
int main(void) {
	input();
	SPFA();
	DFS(D);
	cout << pathnum << " " << rescnum << endl;
}

 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号