[POJ3463] Sightseeing(次短路 Heap + Dijkstra)

传送门

用dijkstra比较好,spfa可能有的重复

dis[x][2]:dis[x][0]表示起点到x的最短路、dis[x][1]表示起点到x的次短路;

tot[x][2]:tot[x][0]表示起点到x的最短路条数、tot[x][1]表示起点到x的次短路的条数;

vis[x][2]对应于x和0、1功能为记录该点是否被访问!

那么如何更新最小和次小路呢?显然我们容易想到下面的方法:

1.if(x<最小)更新最小,次小;
2.else if(x==最小)更新方法数;
3.else if(x<次小)更新次小;
4.else if(x==次小)更新方法数;

——代码

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6
  7 using namespace std;
  8
  9 struct heap
 10 {
 11     int x, y, z;
 12     heap(int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z) {}
 13     bool operator < (const heap &rhs) const
 14     {
 15         return y > rhs.y;
 16     }
 17 };
 18
 19 const int MAXM = 10001, MAXN = 1001;
 20 int T, n, m, cnt;
 21 int dis[MAXN][2], head[MAXN], to[MAXM << 1], next[MAXM << 1], val[MAXM << 1], tot[MAXN][2];
 22 priority_queue <heap> q;
 23 bool vis[MAXN][2];
 24
 25 inline int read()
 26 {
 27     int x = 0, f = 1;
 28     char ch = getchar();
 29     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
 30     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
 31     return x * f;
 32 }
 33
 34 inline void add(int x, int y, int z)
 35 {
 36     to[cnt] = y;
 37     val[cnt] = z;
 38     next[cnt] = head[x];
 39     head[x] = cnt++;
 40 }
 41
 42 inline void dijkstra(int s)
 43 {
 44     int i, u, v, d, p;
 45     heap now;
 46     memset(vis, 0, sizeof(vis));
 47     memset(tot, 0, sizeof(tot));
 48     memset(dis, 127 / 3, sizeof(dis));
 49     dis[s][0] = 0;
 50     tot[s][0] = 1;
 51     q.push(heap(s, 0, 0));
 52     while(!q.empty())
 53     {
 54         now = q.top();
 55         q.pop();
 56         u = now.x;
 57         p = now.z;
 58         if(vis[u][p]) continue;
 59         vis[u][p] = 1;
 60         for(i = head[u]; i ^ -1; i = next[i])
 61         {
 62             v = to[i];
 63             if(dis[v][0] > dis[u][p] + val[i])
 64             {
 65                 dis[v][1] = dis[v][0];
 66                 tot[v][1] = tot[v][0];
 67                 dis[v][0] = dis[u][p] + val[i];
 68                 tot[v][0] = tot[u][p];
 69                 q.push(heap(v, dis[v][0], 0));
 70                 q.push(heap(v, dis[v][1], 1));
 71             }
 72             else if(dis[v][0] == dis[u][p] + val[i]) tot[v][0] += tot[u][p];
 73             else if(dis[v][1] > dis[u][p] + val[i])
 74             {
 75                 dis[v][1] = dis[u][p] + val[i];
 76                 tot[v][1] = tot[u][p];
 77                 q.push(heap(v, dis[v][1], 1));
 78             }
 79             else if(dis[v][1] == dis[u][p] + val[i]) tot[v][1] += tot[u][p];
 80         }
 81     }
 82 }
 83
 84 int main()
 85 {
 86     int i, j, x, y, z, s, t;
 87     T = read();
 88     while(T--)
 89     {
 90         n = read();
 91         m = read();
 92         cnt = 0;
 93         memset(head, -1, sizeof(head));
 94         for(i = 1; i <= m; i++)
 95         {
 96             x = read();
 97             y = read();
 98             z = read();
 99             add(x, y, z);
100         }
101         s = read();
102         t = read();
103         dijkstra(s);
104         if(dis[t][1] == dis[t][0] + 1) tot[t][0] += tot[t][1];
105         printf("%d\n", tot[t][0]);
106     }
107 }

时间: 2024-10-10 05:13:40

[POJ3463] Sightseeing(次短路 Heap + Dijkstra)的相关文章

poj3463 Sightseeing——次短路计数

题目:http://poj.org/problem?id=3463 次短路计数问题,在更新最短路的同时分类成比最短路短.长于最短路而短于次短路.比次短路长三种情况讨论一下,更新次短路: 然而其实不必被"同时"限制,否则就容易像我一开始一样写挂... 像拆点一样把最短路和次短路完全分开,放进 dijkstra 的优先队列里,真是巧妙: 还要注意一点是直接更新最短路之后要把它的次短路也加进优先队列里,因为次短路同时也被更新了. 代码如下: #include<iostream>

poj3463 Sightseeing --- dij最短路和次短路

最短路好题啊. 题目给定起点和终点,要求最短路和次短路(要求次短路只比最短路大1)的道路数量. 重点在于次短路如何处理是最高效的呢 这就要求对dij算法路径更新的理解了. 我们用一个数组记录最短路,一个数组记录次短路. 每次对当前最短边,先更新最短路,更新不了最短路再更新次短路. 每条边处理两次,这样就可以在2n×n的复杂度内求得最短路和次短路了. #include<cstdio> #include<cstring> #include<queue> #include&l

Heap+Dijkstra堆优化的Dijkstra

前面说到"原生的Dijkstra",由于Dijkstra采用的是贪心策略,在贪心寻找当前距离源结点最短的结点时需要遍历所有的结点,这必然会导致效率的下降,时间复杂度为n^n.因此当数据量较大时会消耗较长时间.为了提高Dijkstra的效率,只有对Dijkstra的贪心策略进行改进. 由于Dijkstra采用的贪心策略是每次寻找最短距离的结点并将其放入存放所有已知最短距离结点的S集合中,可以联想到堆以及优先级队列这些数据结构,这些结构都能非常高效地提供当前状态距离最短的结点.实践也可以证

UVA 658 It&#39;s not a Bug, it&#39;s a Feature! (单源最短路,dijkstra+优先队列,变形,经典)

题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了:要打多久才能无bug?(同1补丁可重复打) 分析: n<=20,那么用位来表示bug的话有220=100万多一点.不用建图了,图实在太大了,用位图又不好玩.那么直接用隐式图搜索(在任意点,只要满足转移条件,任何状态都能转). 但是有没有可能每个状态都要搜1次啊?那可能是100万*100万啊,这样出题

HDU2544 最短路 【Dijkstra】

最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 31182    Accepted Submission(s): 13456 Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找

uva 10099 The Tourist Guide(单源最短路/spfa/dijkstra)

题目: 链接:点击打开链接 题意: 思路: 代码: #include <iostream> #include <cstring> #include <cstdio> using namespace std; int map[101][101]; void floyd(int n) { for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) map[i][j] = m

ACM:最短路,dijkstra,邻接表的建立,使用邻接表跟优先队列的dijkstra,Bellman-Ford,Floyd。。

(一)dijkstra,邻接矩阵 所有边权均为正,不管有没有环,求单个源点出发,到所有节点的最短路.该方法同时适用于有向图和无向图. #include <iostream> #include <string> #include <stack> using namespace std; const int MAXN = 1000; const int INF = 100000000; int n, m; int maze[MAXN][MAXN], vis[MAXN], d

最短路算法(dijkstra,bellman_ford,floyd)

最短路算法 dijkstra(初级的最短路算法,适合稠密图,可用邻接表优化) bool relax(int u,int v) { double tmp=max(dist[u],edge[u][v]); if(tmp<dist[v]){ dist[v]=tmp; } } void dijkstra() { memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++){ int x; double mindist=INF; for(int j=0;j<n;j

hdu 2544 最短路 (dijkstra,floyd)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 题目大意:找到两点间最短的距离值. 代码一:(dijkstra算法) 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 int n,Min,node[105],visit[105],map[105][105]; 5 void set() 6 { 7 for (int i=1; i<=n; i