单源最短路

Feature


There are two different situation: one is that the graph has negative weight edges, the other is not. Always remember that only in the situation that there isn't any circuit such that its weights is negative can the graph has the shortest way.

Facing two different situation, we have two algorithm.

Dijkstra


Just like the detail in Prim, using Heap will make our algorithm faster. And the core of the algorithm is still greedy algorithm.

Bellman-Ford


When we meet with the situation that there may exist negative weights edge, what's more it may cause the appearance of the negative weight loop.

Bellman-Ford algorithm can deal with the situation that negative weight edge happen, and it can judge for us whether there is a shortest way in the graph.

There are two different version of Bellman-Ford. And the one which queue has a better efficiency than the other one in Finding Negative Loop

OJ Practise


POJ 2387


Learn a new skill that can set the elements in array to a number that can be thought as INF. 😉

 memset(arrary, 0x3f, sizeof(arrar));

//other skill:

memset(arr,0x7F,sizeof(arr)); //2139062143,max number memset can make for int 
memset(arr,0x80,sizeof(arr)); //set int to -2139062144 

//for double:
memset(arr,0x7F,sizeof(arr)); //set double to 1.38242e+306
memset(arr,0xFE,sizeof(arr)); //set double to -5.31401e+303
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

const int maxn= 1e3+5;
const int mant= 2e3+5;

typedef pair<int, int> P;
struct edge
{
	int to;
	int lth;
	edge(int t, int lth) : to(t), lth(lth){}
	bool operator < (const edge &eg) const
	{
		return lth> eg.lth;
	}
};
class Dijkstra
{
	int T, N, sum;
	priority_queue<P, vector<P>, greater<P> > Q;
	vector<edge> G[maxn];
	int dst[maxn];
	bool done[maxn];
	void Init()
	{
		memset(dst, 0x3f, sizeof(dst));
		memset(done, 0, sizeof(done));
		for (int i= 0; i< N; ++i){
			G[i].clear();
		}
		sum= 0;
	}
	void Read()
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		AddEdge(u, v, w);
	}
	void AddEdge(int u, int v, int w)
	{
		G[u].push_back(edge(v, w));
		G[v].push_back(edge(u, w));
	}
public:
	void dijkstra(const int s)
	{
		dst[s]= 0;
		Q.push(P(0, s));

		while (!Q.empty()){
			P tmp= Q.top();
			Q.pop();
			int dest= tmp.second;
			if (done[dest]){
				continue;
			}
			done[dest]= true;
			for (int i= 0; i< int(G[dest].size()); ++i){
				edge e= G[dest][i];
				if (!done[e.to] && dst[e.to]> dst[dest]+ e.lth){
					dst[e.to]= dst[dest]+ e.lth;
					Q.push(P(dst[e.to], e.to));
				}
			}
		}
	}
	void Solve()
	{
		while(2== scanf("%d %d", &T, &N)){
			Init();
			for (int i= 0; i< T; ++i){
				Read();
			}
			dijkstra(1);
			printf("%d\n", dst[N]);
		}
	}
};
int main()
{
	Dijkstra poj2387;
	poj2387.Solve();
	return 0;
}

POJ 2240 & ZOJ 1092


Nice problem, to use queue optimization, we must cooperate with Union-Find Set. And this problem is subtle because we can use the Bellman-Ford which is aimed for find the shortest way, however, this question is trying to find whether or not ther is a negative loop, so it create opportunity to use Bellman-Ford.

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
#include <string>
#include <cstring>
using namespace std;

const int maxn= 30+3;
const int maxm= maxn*maxn;

struct edge
{
	int to;
	float dor;
	edge(int to, float dor) : to(to), dor(dor){}	
};
class BellmanFord{
private:
	int n, m;
	vector<edge> G[maxn];
	queue<int> Q;
	float dolr[maxn];
	bool In[maxn];
	int danger[maxn];
	float rij;
	int par[maxn];
	void Init()
	{
		memset(In, 0, sizeof(In));
		memset(danger, 0, sizeof(danger));
		memset(dolr, 0, sizeof(dolr));
		for (int i= 0; i< n; ++i){
			G[i].clear();
			par[i]= i;
		}
	}
	int Find(int x)
	{
		if (x==par[x]){
			return x;
		}
		return par[x]= Find(par[x]);
	}
	void Union(int fa, int son)
	{
		fa= Find(fa);
		son= Find(son);
		if (fa!= son){
			par[son]= fa;
		}
	}
	bool bellmanFord()
	{
		for (int i= 0; i< n; ++i){
			if (i== Find(i)){
				dolr[i]= 1.0;
				In[i]= true;
				Q.push(i);
			}
		}

		while (!Q.empty()){
			int dest= Q.front();
			Q.pop();
			In[dest]= false;
			for (int i= 0; i< int(G[dest].size()); ++i){
				edge e= G[dest][i];
				if (dolr[e.to]< dolr[dest]*e.dor){
					dolr[e.to]= dolr[dest]*e.dor;
					if (!In[e.to]){
						Q.push(e.to);
						In[e.to]= true;
						if (++(danger[e.to])> n){
							return true;
						}
					}
				}
			}
		}

		return false;
	}
public:
	void Solve()
	{
		string cnty, cnty1;
		int kase= 0;
		while (EOF!= scanf("%d", &n) && n){
			Init();
			map<string, int> bk;
			for (int i= 0; i< n; ++i){
				cin>>cnty;
				bk[cnty]= i;
			}
			scanf("%d", &m);
			for (int i= 0; i< m; ++i){
				cin>>cnty>>rij >>cnty1;
				Union(bk[cnty], bk[cnty1]);
				G[bk[cnty]].push_back(edge(bk[cnty1], rij));
			}
			if (bellmanFord()){
				printf("Case %d: Yes\n", ++kase);
			}
			else{
				printf("Case %d: No\n", ++kase);
			}
		}
	}
};

int main()
{
	BellmanFord bell;
	bell.Solve();
	return 0;
}
posted @ 2019-12-09 17:10  IdiotNe  阅读(60)  评论(0)    收藏  举报