最短路,如果是非负图的话,那么最好就是利用dijkstra去处理最短路的问题,首先是基于贪心算法
找寻最优的点向外扩展,不断寻找最优代价的未扩展的点,逐步扩展,直到到达目标点
优化dijkstra是在寻找最优的点上下功夫
我们拉出来最基本的模板
int dist[MAXN]; bool vis[MAXN]; void dijkstra(int x){ memset(dist,0x3f,sizeof(dist)); memset(vis,0,sizeof(vis)); dist[x]=0; for(int i=1;i<=n;i++){ int max=0x3f3f3f3f,aim=x; for(int j=1;j<=n;j++){ if(!vis[j] && dist[j]<max){ max=dist[j],aim=j; } } vis[aim]=true; for(int j=1;j<=n;j++){ if(!vis[j]){ dist[j]=std::min(dist[j],dist[aim]+pic[aim][j]); } } } }
实际上最重要是记录dist数组以及vis数组,一个存储当前维护的值,另一个是标记是否已经访问
按照dijkstra算法的思想,就是先初始化dist和vis数组,然后将开始的原点dist变为0,然后依次N次更新N个节点,让寻找最优的dist的节点,然后不断标记,进而扩展开来
问题还是在于初始化以及优化,还有关键的更新结点时所要做决策
POJ1797
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <utility> const int MAXN = 1005, MAXM = (int)1e6 + 5; const int INF = 0x3f3f3f3f; int map[MAXN][MAXN]; int n, m, tot; int dist[MAXN]; bool vis[MAXN]; /* int ver[MAXM],next[MAXM],edge[MAXM],head[MAXN],dist[MAXN]; bool vis[MAXN]; void add(int x,int y,int z){ ver[++tot]=y,edge[tot]=z,next[tot]=head[x],head[x]=tot; } */ void dijkstra() { memset(vis, 0, sizeof(vis)); std::priority_queue<std::pair<int, int>> q; dist[1] = INF; for(int i=2;i<=n;i++) dist[i]=map[1][n]; q.push(std::make_pair(0, 1)); while (q.size()) { //std::cout<<q.top().first<<" "<<q.top().second<<"\n"; int x = q.top().second; q.pop(); if (vis[x]) continue; vis[x] = true; for (int i = 1; i <= n; i++) { if(!vis[i] && map[x][i]>0){ int min = std::min(map[x][i], dist[x]); if (min > dist[i]) { dist[i] = min; q.push(std::make_pair(dist[i], i)); } } } } } int main() { int T; std::cin >> T; for (int casei = 1; casei <= T; casei++) { memset(map, 0xcf, sizeof(map)); std::cin >> n >> m; for (int i = 1; i <= m; i++) { int x, y, z; scanf("%d%d%d", &x, &y, &z); map[x][y] = std::max(map[x][y], z); map[y][x] = std::max(map[y][x], z); } dijkstra(); printf("Scenario #%d:\n", casei); std::cout << dist[n] << "\n\n"; } return 0; }
dijkstra堆优化实际上就是对未访问结点在已访问结点更新的那些节点,找出最优的节点来标记,进而进一步扩展,只需要维护最优值利用堆的优化,减少时间复杂度
注意对优先队列的使用。