http://poj.org/problem?id=3255
题意:
给你一张图,起点为1,终点为n 。求从1到n的次短路。(这里每条边可以重复走)
思路:
两遍最短路算法分别求出1到所有点的最短距离,n到所有点的最短距离。然后枚举每一条边找出第二短路。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 200004 #define N 5007 using namespace std; //freopen("din.txt","r",stdin); struct node { int v,w; int next; }g[M]; int head[N],ct; int dis1[N],dis2[N]; bool vt[N]; int n,m; void add(int u,int v, int w) { g[ct].v = v; g[ct].w = w; g[ct].next = head[u]; head[u] = ct++; g[ct].v = u; g[ct].w = w; g[ct].next = head[v]; head[v] = ct++; } void spfa1(int s) { int i; for (i = 0; i < n; ++i) { dis1[i] = inf; vt[i] = false; } dis1[s] = 0; vt[s] = true; queue<int>q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int w = g[i].w; //printf("%d %d\n",u,v); if (dis1[v] > dis1[u] + w) { dis1[v] = dis1[u] + w; if (!vt[v]) { vt[v] = true; q.push(v); } } } } } void spfa2(int s) { int i; for (i = 0; i < n; ++i) { dis2[i] = inf; vt[i] = false; } dis2[s] = 0; vt[s] = true; queue<int>q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int w = g[i].w; if (dis2[v] > dis2[u] + w) { dis2[v] = dis2[u] + w; if (!vt[v]) { vt[v] = true; q.push(v); } } } } } int main() { freopen("din.txt","r",stdin); int i,j; int x,y,z; while (~scanf("%d%d",&n,&m)) { CL(head,-1); ct = 0; for (i = 0; i < m; ++i) { scanf("%d%d%d",&x,&y,&z); add(x - 1,y - 1,z); } //printf("ZUIDUANLU = %d\n",dis1[n - 1]); spfa1(0); //printf("ZUIDUANLU = %d\n",dis1[n - 1]); spfa2(n - 1); //printf("%d %d\n",dis1[n - 1],dis2[0]); int minB = inf; int minA = inf; for (i = 0; i < n; ++i) { for (j = head[i]; j != -1; j = g[j].next) { int v = g[j].v; int w = g[j].w; int m = dis1[i] + dis2[v] + w; int tmp = 0; //这样枚举才对 minA存的最短路径 if (minA > m) { tmp = minA; minA = m; m = tmp; }//minB存的第二短路径 if (minB > m && m != minA) { minB = m; } //不知道为什么这样枚举就错了..... /*if (dis1[n - 1] < dis1[i] + dis2[v] + w) { disMax = min(disMax,dis1[i] + dis2[v] + w); }*/ } } printf("%d\n",minB); } return 0; }
第二种思路:dis[i][0]表示最短路 dis[i][1]表示次短路 然后一边SPFA 队列里存放来自最短路或者次短路的点的值,然后更新最短路或者次短路。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 200004 #define N 5007 using namespace std; //freopen("din.txt","r",stdin); struct node { int v,w; int next; }g[M]; int head[N],ct; struct t_node { int x,dis; }p1,p2; int dis[N][2]; bool vt[N][2]; int n,m; void add(int u,int v,int w) { g[ct].v = v; g[ct].w = w; g[ct].next = head[u]; head[u] = ct++; g[ct].v = u; g[ct].w = w; g[ct].next = head[v]; head[v] = ct++; } void spfa(int s) { int i; for (i = 1; i <= n; ++i) { dis[i][0] = dis[i][1] = inf; } dis[s][0] = 0; queue<t_node>q; p1.x = s; p1.dis = 0; q.push(p1); while (!q.empty()) { p2 = q.front(); q.pop(); int u = p2.x; for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int w = p2.dis + g[i].w; if (dis[v][0] > w)//更新最短路 { if (dis[v][0] != inf)//更新次短路 { dis[v][1] = dis[v][0]; p1.dis = dis[v][1]; p1.x = v; q.push(p1); } dis[v][0] = w; p1.dis = w; p1.x = v; q.push(p1); } else if (dis[v][1] > w)//更新次短路 { dis[v][1] = w; p1.dis = w; p1.x = v; q.push(p1); } } } } int main() { //freopen("din.txt","r",stdin); int i; int x,y,z; while (~scanf("%d%d",&n,&m)) { CL(head,-1); ct = 0; for (i = 0; i < m; ++i) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); } spfa(1); // printf("<><>%d\n",dis[n][0]); //for (i = 1; i <= n; ++i) printf("%d\n",dis[n][1]); } return 0; }
第三种思路:
求第K短路通用算法最短路+A*启发式搜索
(注:以下部份资料来源于网上)
所谓A*就是启发是搜索 说白了就是给搜索一个顺序使得搜索更加合理减少无谓的搜索. 如何来确定搜索的顺序?..也就是用一个值来表示 这个值为f[n]..每次搜索取f[x]最小的拓展 那么这个f[n]=h[n]+g[n]
其中f(n) 是节点n的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说详细 点,g(n)代表了搜索的广度的优先趋势。但是当h(n) >> g(n)时,可以省略g(n),而提高效率。
A*算法的估价函数可表示为:
f’(n) = g’(n) + h’(n)
这里,f’(n)是估价函数,g’(n)是起点到终点的最短路径值,h’(n)是n到目标的最短路经的启发值。由 于这个f’(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g’(n),但 g(n)>=g’(n) 才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h’(n),但h(n)<=h’(n)才可(这一点特别的重 要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 200004 #define N 5007 using namespace std; //freopen("din.txt","r",stdin); struct node { int v,w; int next; }g[M]; int head[N],ct; int dis[N]; bool vt[N]; int n,m; struct A_node { int v,g; bool operator < (A_node b) const { return (g + dis[v]) > (b.g + dis[b.v]); } }p1,p2; void add(int u,int v,int w) { g[ct].v = v; g[ct].w = w; g[ct].next = head[u]; head[u] = ct++; g[ct].v = u; g[ct].w = w; g[ct].next = head[v]; head[v] = ct++; } void spfa(int s) { int i; for (i = 1; i <= n; ++i) { dis[i] = inf; vt[i] =false; } dis[s] = 0; vt[s] = true; queue<int>q; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vt[u] = false; for (i = head[u]; i != - 1; i = g[i].next) { int v = g[i].v; int w = g[i].w; if (dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if (!vt[v]) { vt[v] = true; q.push(v); } } } } } int cnt[N]; priority_queue<A_node> pq; int A_star(int s,int t,int k) { int i; int ans = 0; CL(cnt,0); while (!pq.empty()) pq.pop(); if (s == t) k++;//注意当s==t时需要计算K+1短路,因为s到t这条距离为0的路不能算在这K短路中,这时只需将K++ p1.g = 0; p1.v = s; pq.push(p1); while (!pq.empty()) { p2 = pq.top(); pq.pop(); int u = p2.v; int gi = p2.g; cnt[u]++; if (cnt[u] > k) continue; if (cnt[t] == k) { ans = gi; break; } for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int w = g[i].w; p1.v = v; p1.g = gi + w; pq.push(p1); } } return ans; } int main() { //freopen("din.txt","r",stdin); int i; int x,y,z; while (~scanf("%d%d",&n,&m)) { CL(head,-1); ct = 0; for (i = 0; i < m; ++i) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); } spfa(n); printf("%d\n",A_star(1,n,2)); } return 0; }