1003 emergency (three solutions of Dijkstra, Bellman Ford and SPFA)

Posted by leeroy1 on Tue, 21 Dec 2021 11:15:58 +0100

catalogue

1. Dijkstra solution

2. Bellman Ford solution

3. SPFA solution

4. Dijkstra solution AC code

5. Bellman Ford solution AC code

6. Non full score (19 / 25) code of SPFA solution

1. Dijkstra solution

This problem involves not only the basic solution, but also the second standard (cumulative number of troops) and recording the number of shortest paths. These are modified in the if statement of the tight path. I think my nested judgment writing method here (judge whether the node has been accessed before proceeding to the next step) is clearer than the compound conditional sentence in the book

//Tension path
for(int j=0;j<city[minC].nbr.size();j++){
	int nbr = city[minC].nbr[j].no;
	if(vis[nbr]==0){
		if(d[minC]+city[minC].nbr[j].dis<d[nbr]){
			n[nbr] = n[minC];
			d[nbr] = d[minC]+city[minC].nbr[j].dis;
			t[nbr] = t[minC] + city[nbr].teamN;
		}else if(d[minC]+city[minC].nbr[j].dis==d[nbr]){
			n[nbr] += n[minC];
			if(t[minC] + city[nbr].teamN > t[nbr])t[nbr] = t[minC] + city[nbr].teamN;
		}
	}
}	

For the initialization of the starting point, three conditions need to be initialized

//Set the distance from the start point to 0 
d[sCity] = 0;
//Set the number of shortest paths from the starting point to 1
n[sCity] = 1;
//Set the number of troops at the starting point to own
t[sCity] = city[sCity].teamN;

It is worth noting that for the update of the number of shortest paths, if there is an optimization scheme, the number of shortest paths of the current node should be assigned to the number of shortest paths of the predecessor node instead of 1. If there is an equally excellent scheme, the number of shortest paths of the current node should increase the number of shortest paths of the predecessor node instead of 1.

2. Bellman Ford solution

BF algorithm can judge whether there is a reachable negative ring, but it is not used in the context of this problem. It is mainly divided into tight part and negative ring part. The same thorny problem is how to deal with the number of shortest paths. When you encounter tension, you can directly update the successor nodes with the number of paths of the predecessor. This is the same as Dijkstra, but when you encounter the same optimization strategy, it is different. At first, I won't do it. I read the reference book to understand. You need to set a leading node table set < int > pre [maxn]. If you encounter the same optimal path, first add the current leading node, then clear the number of shortest paths of the current node (very easy to forget), and traverse the set of leading nodes. The sum of the number of shortest paths of all leading nodes is the number of shortest paths of the current node. In addition, when encountering a better path, you need to empty the precursor node set first, and then insert the current precursor node.

if(vis[no]==0){
	if(d[j]+dis<d[no]){
		n[no] = n[j];
		t[no] = t[j]+city[no].teamN;
		d[no] = d[j]+dis;
		pre[no].clear();
		pre[no].insert(j);  
	}else if(d[j]+dis==d[no]){
		pre[no].insert(j);
		n[no] = 0; 
		for(set<int>::iterator it = pre[no].begin();it!=pre[no].end();it++){
			n[no] += n[*it];
		}
		if(t[no]<t[j]+city[no].teamN)t[no] = t[j]+city[no].teamN;
	}
}

3. SPFA solution

The BFS version of SPFA is used here. The law used is "d[u] changes, and only the shortest path of the successor node of u may change". Therefore, after an optimization, the currently optimized node is put into the queue. As for the number of updates, this is actually an improved BF algorithm, which is the same as BF. But I don't know why there are two test points with wrong answers. Try rewriting it into DFS in the future.

while(!Q.empty()){
		int now = Q.front();
		Q.pop();
		inq[now] = 0;//It's not on the team now
		for(int i=0;i<city[now].nbr.size();i++){
			int no = city[now].nbr[i].no;
			int dis  = city[now].nbr[i].dis;
			if(d[now]+dis<d[no]){
				d[no] = d[now]+dis;
				t[no] = t[now]+city[no].teamN;
				n[no] = n[now];
				pre[no].clear();
				pre[no].insert(now);
				if(inq[no]==0){
					Q.push(no);
					inq[no] = 1;
					inqN[no]++;
					if(inqN[no]>=cityN)return false;	
				}
			}else if(d[now]+dis==d[no]){
				if(t[no] < t[now]+city[no].teamN)t[no] = t[now]+city[no].teamN;
				pre[no].insert(now);
				n[no] = 0;
				for(set<int>::iterator it = pre[no].begin();it!=pre[no].end();it++){
					n[no] += n[*it];
				}
			} 
		} 
	}

4. Dijkstra solution AC code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;

const int INF = 1000000000;//The 9th power of 10 
const int maxn = 510;
const double eps = 1e-3;

struct Node{
	int no;
	int dis;
	Node(int _no,int _dis):no(_no),dis(_dis){}
	
};

struct City{
	vector<Node> nbr;
	int teamN;
}city[maxn];

int cityN,roadN,sCity,dCity;

bool vis[maxn] = {0};
int d[maxn]; 
int t[maxn] = {0};//The array t stores the maximum number of rescue teams accumulated on the shortest path
int n[maxn] = {0};//n number of shortest paths stored

void Dijkstra(){
	//Fill the shortest distance path array (the other three have been initialized)
	fill(d,d+cityN,INF);
	//Set the distance from the start point to 0 
	d[sCity] = 0;
	//Set the number of shortest paths from the starting point to 1
	n[sCity] = 1;
	//Set the number of troops at the starting point to own
	t[sCity] = city[sCity].teamN;	
	
	for(int i=0;i<cityN;i++){//One node at a time 
		//Find the array with the smallest distance from the current array
		int minD = INF,minC  = -1;//Shortest distance and corresponding city number
		for(int j=0;j<cityN;j++){
			if(d[j]<minD&&vis[j]==0){
				minD = d[j];
				minC = j;
			} 
		} 
		 
		if(minC==-1)return;//It indicates that all nodes have joined S 
		else vis[minC] = 1;
		 
		//Tension path
		for(int j=0;j<city[minC].nbr.size();j++){
			int nbr = city[minC].nbr[j].no;
			if(vis[nbr]==0){
				if(d[minC]+city[minC].nbr[j].dis<d[nbr]){
					n[nbr] = n[minC];
					d[nbr] = d[minC]+city[minC].nbr[j].dis;
					t[nbr] = t[minC] + city[nbr].teamN;
				}else if(d[minC]+city[minC].nbr[j].dis==d[nbr]){
					n[nbr] += n[minC];
					if(t[minC] + city[nbr].teamN > t[nbr])t[nbr] = t[minC] + city[nbr].teamN;
				}
			}
		}		 
	}	
}


int main(){
	
	scanf("%d %d %d %d",&cityN,&roadN,&sCity,&dCity);
	
	//Read in the number of rescue teams in each city 
	for(int i=0;i<cityN;i++){
		scanf("%d",&city[i].teamN);
	}
	//Read in the length of each road
	for(int i=0;i<roadN;i++){
		int c1,c2,len;
		scanf("%d %d %d",&c1,&c2,&len);
		Node* n1 = new Node(c1,len);
		city[c2].nbr.push_back(*n1);
		Node* n2 = new Node(c2,len);
		city[c1].nbr.push_back(*n2);
	}
	
	//Call Dijkstra algorithm
	Dijkstra(); 
	
	printf("%d %d\n",n[dCity],t[dCity]); 
	
	return 0; 
}

5. Bellman Ford solution AC code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;

const int INF = 1000000000;//The 9th power of 10 
const int maxn = 510;
const double eps = 1e-3;

struct Node{
	int no;
	int dis;
	Node(int _no,int _dis):no(_no),dis(_dis){}
	
};

struct City{
	vector<Node> nbr;
	int teamN;
}city[maxn];

int cityN,roadN,sCity,dCity;

bool vis[maxn] = {0};
int d[maxn]; 
int t[maxn] = {0};//The array t stores the maximum number of rescue teams accumulated on the shortest path
int n[maxn] = {0};//n number of shortest paths stored

set<int> pre[maxn];//It stores the precursor node of each node, which is unique to BF and is used to update the number of shortest paths 

bool BF(){
	fill(d,d+cityN,INF);
	d[sCity] = 0;
	n[sCity] = 1;
	t[sCity] = city[sCity].teamN;
	
	//Perform tightening operation
	for(int i=0;i<cityN-1;i++){
		for(int j=0;j<cityN;j++){
			for(int k=0;k<city[j].nbr.size();k++){
				int no = city[j].nbr[k].no;
				int dis = city[j].nbr[k].dis;
				if(vis[no]==0){
					if(d[j]+dis<d[no]){
						n[no] = n[j];
						t[no] = t[j]+city[no].teamN;
						d[no] = d[j]+dis;
						pre[no].clear();
						pre[no].insert(j);  
					}else if(d[j]+dis==d[no]){
						pre[no].insert(j);
						n[no] = 0; 
						for(set<int>::iterator it = pre[no].begin();it!=pre[no].end();it++){
							n[no] += n[*it];
						}
						if(t[no]<t[j]+city[no].teamN)t[no] = t[j]+city[no].teamN;
					}
				}
			}
		}
	}
	
	//Judge whether there is reachable negative ring
	for(int i=0;i<cityN;i++){
		for(int j=0;j<city[i].nbr.size();j++){
			int no = city[i].nbr[j].no;
			int dis = city[i].nbr[j].dis;
			if(d[no]>d[i]+dis)return false;
		}
	}
	
	return true;
	 
}


int main(){
	
	scanf("%d %d %d %d",&cityN,&roadN,&sCity,&dCity);
	
	//Read in the number of rescue teams in each city 
	for(int i=0;i<cityN;i++){
		scanf("%d",&city[i].teamN);
	}
	//Read in the length of each road
	for(int i=0;i<roadN;i++){
		int c1,c2,len;
		scanf("%d %d %d",&c1,&c2,&len);
		Node* n1 = new Node(c1,len);
		city[c2].nbr.push_back(*n1);
		Node* n2 = new Node(c2,len);
		city[c1].nbr.push_back(*n2);
	}
	
	//Call BF algorithm
	int res = BF();
	
	if(res)printf("%d %d\n",n[dCity],t[dCity]); 
	
	return 0; 
}

6. Non full score (19 / 25) code of SPFA solution

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;

const int INF = 1000000000;//The 9th power of 10 
const int maxn = 510;
const double eps = 1e-3;

struct Node{
	int no;
	int dis;
	Node(int _no,int _dis):no(_no),dis(_dis){}
	
};

struct City{
	vector<Node> nbr;
	int teamN;
}city[maxn];

int cityN,roadN,sCity,dCity;

bool vis[maxn] = {0};
int d[maxn]; 
int t[maxn] = {0};//The array t stores the maximum number of rescue teams accumulated on the shortest path
int n[maxn] = {0};//n number of shortest paths stored

set<int> pre[maxn];//It stores the precursor node of each node, which is unique to BF and is used to update the number of shortest paths 

bool inq[maxn] = {0};
int inqN[maxn] = {0};//Number of times to queue 

bool SPFA(){
	fill(d,d+cityN,INF);
	d[sCity] = 0;
	n[sCity] = 1;
	t[sCity] = city[sCity].teamN;
	
	queue<int> Q;
	Q.push(sCity);
	inq[sCity] = 1;
	inqN[sCity]++;
	
	while(!Q.empty()){
		int now = Q.front();
		Q.pop();
		inq[now] = 0;//It's not on the team now
		for(int i=0;i<city[now].nbr.size();i++){
			int no = city[now].nbr[i].no;
			int dis  = city[now].nbr[i].dis;
			if(d[now]+dis<d[no]){
				d[no] = d[now]+dis;
				t[no] = t[now]+city[no].teamN;
				n[no] = n[now];
				pre[no].clear();
				pre[no].insert(now);
				if(inq[no]==0){
					Q.push(no);
					inq[no] = 1;
					inqN[no]++;
					if(inqN[no]>=cityN)return false;	
				}
			}else if(d[now]+dis==d[no]){
				if(t[no] < t[now]+city[no].teamN)t[no] = t[now]+city[no].teamN;
				pre[no].insert(now);
				n[no] = 0;
				for(set<int>::iterator it = pre[no].begin();it!=pre[no].end();it++){
					n[no] += n[*it];
				}
			} 
		} 
	}
	
	return true;
}


int main(){
	
	scanf("%d %d %d %d",&cityN,&roadN,&sCity,&dCity);
	
	//Read in the number of rescue teams in each city 
	for(int i=0;i<cityN;i++){
		scanf("%d",&city[i].teamN);
	}
	//Read in the length of each road
	for(int i=0;i<roadN;i++){
		int c1,c2,len;
		scanf("%d %d %d",&c1,&c2,&len);
		Node* n1 = new Node(c1,len);
		city[c2].nbr.push_back(*n1);
		Node* n2 = new Node(c2,len);
		city[c1].nbr.push_back(*n2);
	}
	
	//Call BF algorithm
	int res = SPFA();
	
	if(res)printf("%d %d\n",n[dCity],t[dCity]); 
	
	return 0; 
}

Topics: Algorithm dijkstra SPFA