Dijkstra + 堆优化

Dijkstra算法原理请见:最短路径问题(Dijkstra解法)

该算法对于稠密图更加有效:

对于给出具有非负权重的边和源顶点S的图G,算法可在O(mlogn)时间内找出从s点到其他每一个顶点的距离。

如果图是稠密的,即对于某个ε>0,m>=n^(1+ε),可以被改善在O(m/ε)内执行。(m为图的边数,n为图的定点数)

最小堆模板:

struct HeapElement {
	// key存储顶点序号,value存储到该顶点的最短距离 
	int key, value;
};
struct MinHeap {
	HeapElement heap[MAXN];
	int position[MAXN];
	int size; // 顶点数
	void init() { 
		heap[size=0].value = -INF; 
		memset(position, 0, sizeof(position));
	}
	void insert(int key, int value) {
		heap[++size].key = key;
		heap[size].value = value;
		position[key] = size;
		siftUp(size);
	}
	void decrease(int index) {
		int x = heap[index].value;
		int y = heap[size].value;
		-- size;
		if (index == size+1)
			return;
		
		swap(heap[index], heap[size+1]);
		if (y >= x) {
			siftDown(index);	
		} else {
			siftUp(index);	
		}
	}
	int delmin() {
		int x = heap[1].key;
		decrease(1);
		return x;
	}
	void siftUp(int index) {
		while (index > 1) {
			if (heap[index].value < heap[index/2].value) {
				swap(heap[index],heap[index/2]);	
			} else {
				break;
			}
			index /= 2;
		}
	}
	void siftDown(int index) {
		while (index*2 <= size) {
			index *= 2;
			if (index < size && heap[index].value > heap[index+1].value) {
				++ index;
			}
			if (heap[index].value < heap[index/2].value) {
				swap(heap[index],heap[index/2]);
			} else {
				break;
			}
		}
	}
	void makeHeap() {
		for (int i = size/2; i > 0; -- i) 
			siftDown(i);
	}
	void swap(HeapElement &a, HeapElement &b) {
		HeapElement temp = a;
		a = b;
		b = temp;
		int tmp = position[a.key];
		position[a.key] = position[b.key];
		position[b.key] = tmp;
	}
}H;

代码实现:(hdu2544)

#include <iostream>
#define INF 0x7FFFFFFF
using namespace std;

const int SIZE = 105;
int dist[SIZE];
int G[SIZE][SIZE];
bool vis[SIZE];
struct HeapElement {
    int key, value;    
};
void swap(HeapElement &ha, HeapElement &hb) {
    int key = ha.key;
    int value = ha.value;
    ha.key = hb.key;
    ha.value = hb.value;
    hb.key = key;
    hb.value = value;
};
// 使用邻接表储存图,线性表储存堆 
struct MinHeap {
    HeapElement heap[SIZE];
    int n;    // 顶点数    
        
    void makeheap() {
        for (int i = n/2; i > 0; -- i)
            siftDown(i);
    };
    void siftUp(int index) {
        int k = index;
        while (k > 1) {
            if (heap[k].value < heap[k/2].value) {
                swap(heap[k],heap[k/2]);    
            } else {
                break;    
            }
            k /= 2;    
        }
    };
    void siftDown(int index) {
        int k = index;
        while (k*2 <= n) {
            k *= 2;
            if (k < n && heap[k].value > heap[k+1].value) {
                ++ k;    
            }
            if (heap[k].value < heap[k/2].value) {
                swap(heap[k],heap[k/2]);
            } else {
                break;    
            }    
        }
    };
    void insert(HeapElement element) {
        heap[++n] = element;
        siftUp(n);    
    };
    void decrease(int index) {
        int x = heap[index].value;
        int y = heap[n].value;
        n -= 1;
        
        // 若删除节点位于最末位置,则删除成功,无需其他操作。 
        if (index == n+1) 
            return;
        
        heap[index] = heap[n+1];
        if (y >= x) {
            siftDown(index);    
        } else {
            siftUp(index);    
        }
    };
    int decreaseMin() {
        int x = heap[1].key;
        decrease(1);
        return x;
    };
}H;

void dijkstra(int src, int n) {
    int i, j, w;
    bool flag;
    
    for (i = 1; i <= n; ++ i) {
        if (G[i][src] != INF) {
            dist[i] = G[src][i];
            HeapElement h = {i, dist[i]};
            H.insert(h);    
        } else {
            dist[i] = INF;    
        }    
    }
    
    memset(vis, false, sizeof(vis));
    vis[src] = true;
    dist[src] = 0;
    

    
    for (i = 1; i < n; ++ i) {

        int node = H.decreaseMin();
        vis[node] = true;

        for (w = 1; w <= n; ++ w) {
            flag = false;
            if (!vis[w] && G[node][w] != INF) {
                if (dist[node] < dist[w] - G[node][w]) {
                    dist[w] = dist[node] + G[node][w];
                        
                } 
                for (j = 1; j <= H.n; ++ j) {
                        if (H.heap[j].key == w) {
                            H.heap[j].value = dist[w];
                            flag = true;
                            break;    
                        }    
                    }    
                
                if (!flag) {
                    HeapElement h = {w, dist[w]};
                    H.insert(h);
                } else {
                    H.siftUp(j);
                }
            }
        }    
    }
};

void init(int n) {
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            G[i][j] = INF;
    H.n = 0;
};

int main()
{
    int N, M, a, b, c;
    
    //freopen("C:\\Users\\Smile\\test.txt","r",stdin);
    //freopen("C:\\Users\\Smile\\out.txt", "w", stdout);
    
    while (scanf("%d%d",&N,&M)!=EOF, N&&M) {
        init(N);
        
        for (int i = 0; i < M; ++ i) {
            scanf("%d%d%d",&a,&b,&c);
            if (G[a][b] > c) {
                G[a][b] = c;
                G[b][a] = c;
            }
        }
        
        dijkstra(1, N);
        
        printf("%d\n",dist[N]);    
    }
}
    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/jokes000/article/details/7533715
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞