标签:队列实现 highlight 处理 div add man cond top 题目
最短路最常用的算法有:
单源最短路: Bellman-Ford 算法,Dijkstra 算法,SPFA 算法。
任意两点间最短路:Floyd算法。
Bellman-Ford 可以处理有负边的情况,也可以处理负圈。最多进行V - 1次迭代操作,如果第V次还进行更新操作,说明存在负圈。
Dijkstra 不仅不能处理负圈,连有负边都不能。
Floyd 也可以处理负边的情况。判断负圈只需检查最dp[i][i]是否存在负数的顶点i即可。
SPFA 可以处理负边的情况,是Bellman-Ford的一种队列实现。判断负圈只需判断顶点入队列次数,超过V次就存在负圈。
模板:
const int INF = 0x3f3f3f3f;
int d[MAX_V];//最大顶点数,设置为题目中顶点数的最大值
int V, E;//顶点数;边数
struct Edge{
	int from;
	int to;
	int cost;
     Edge(int _from = 0, int _to = 0, int _cost = 0) : from(_from), to(_to), cost(_cost){} 
}
Edge es[MAX_E];
bool bellman_ford(int s){//true:有负圈 false:没有负圈
	for(int i = 1; i <= V; ++i){//定点编号从1开始
		d[i] = INF;
	}
	d[s] = 0;//d[i]为从s到i的最短路
	for(int i = 1; i < V; ++i){//最多做V-1次
		bool flag = false;
		for(int j = 0; j < E; ++j){
			Edge e = es[i];
			if(d[e.to] > d[e.from] + e.cost){
				d[e.to] = d[e.from] + e.cost;
				flag = true;
			}
		}
		if(!flag)
			return false;
	}
	for(int i = 0; i < E; ++i){
		Edge e = es[i];
		if(d[e.to] > d[e.from] + e.cost)
			return true;
	}
	return false;
}
未优化:O(V2)
const int INF = 0x3f3f3f3f;
int cost[MAX_V][MAX_V];
bool used[MAX_V];//使用过的顶点
int d[MAX_V];//最大顶点数,设置为题目中顶点数的最大值
int prev[MAX_V];//最短路上的前驱顶点
int V;//顶点数
void dijkstra(int s){
	for(int i = 0; i < V; ++i){
		d[i] = INF;
		used[i] = false;
		pre[i] = -1;
	}
	d[s] = 0;
	for(int i = 1; i < V; ++i){//最多走
		int k = -1;
		for(int j = 0; j < V; ++j){
			if(!used[j] && d[j] < d[k]){
				k = j;
                        }
		}
		if(k == -1) break;
		used[k] = true;
		for(int j = 0; j < V; ++j){
			if(d[j] > d[k] + cost[k][j]){
				d[j] = d[k] + cost[k][j];
				prev[j] = k;
			}
		}
	}
}
堆优化:O(ElogV)
const int INF = 0x3f3f3f3f;
int d[MAX_V];//最大顶点数,设置为题目中顶点数的最大值
int V;//顶点数
struct Edge{
	int to;
	int cost;
	Edge(int _v = 0, int _cost = 0) : v(_v), cost(_cost){}
}
typedef pair<int, int> P;
vector<Edge> G[MAX_V];
void dijkstra(int s){
	priority_queue<P, vector<P>, greater<P>> que;
	for(int i = 0; i < V; ++i){
		d[i] = INF;
	}
	d[s] = 0;
	que.push(P(0, s));
	while(!que.empty()){
		P p = que.top();
		que.pop();
		int v = p.second;
		if(d[v] < p.first) continue;
		for(int i = 0; i < G[v].size(); ++i){
			Edge e = G[v][i];
			if(d[e.to] > d[v] + e.cost){
                                d[e.to] = d[v] + e.cost;
				que.push(P(d[e.to], e.to));
			}
		}
	}
}
void addEdge(int s, int t, int cost){
	G[s].push_back(Edge(t, cost));
}
Floyd实质上为dp问题。假设dp[i][j]为i与j之间的最短路,然后依次取集合中剩余点k,比较dp[i][j]和dp[i][k] + dp[k][j],即最短路要么不经过点k,要么经过点k。得到递推式:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])。这是一个O(n3)时间复杂度的算法。
模板:
const int INF = 0x3f3f3f3f;//巧妙设置无穷大值
int dp[MAX_V][MAX_V];//邻接矩阵表 int V;//顶点数 void floyd(){ for(int k = 0; k < V; ++k){ for(int i = 0; i < V; ++i){ for(int j = 0; j < V; ++j){ dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]); } } } }
const int INF = 0x3f3f3f3f;
struct Edge{
	int to;
	int cost;
	Edge(int _v = 0, int _cost = 0) : v(_v), cost(_cost){}
}
vector<Edge> G[MAX_V];
int d[MAX_V];//最大顶点数,设置为题目中顶点数的最大值
bool used[MAX_V];
int cnt[MAX_V];
int pre[MAX_V];
int V;//顶点数
bool SPFA(int s){
	for(int i = 0; i < V; ++i){
		d[i] = INF;
		cnt[i] = 0;
		used[i] = false;
                pre[i] = -1;
	}
	d[s] = 0;
	cnt[i] = 1;
        pre[i] = s;
	used[s] = true;
	queue<int> que;
	que.push(s);
	while(!que.empty()){
		int v = que.front();
		que.pop();
		used[v] = false;
		for(int i = 0; i < G[v].size(); ++i){
			Edge e = G[v][i];
			if(d[e.to] > d[v] + e.cost){
				d[e.to] = d[v] + e.cost;
                                pre[e.to] = v;
				if(!used[v]){
					used[v] = true;
					que.push(v);
					if(++cnt[v] >= V)//入队列次数超过顶点数,则存在负圈
						return true;
				}
			}
		}
	}
	return false;
}
void addEdge(int s, int t, int cost){
	G[s].push_back(Edge(t, cost));
}
标签:队列实现 highlight 处理 div add man cond top 题目
原文地址:http://www.cnblogs.com/Atanisi/p/7648197.html