那HDU的2544作为复习最短路的题目,用不同算法。
迪杰斯特拉
有点像普利姆算法的精简版,不能有负权边
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 99999 #define qmin(a,b) a > b ? b : a //最短路 //迪杰斯特拉 int G[200][200]; int vis[200]; int djs (int n,int s) { int d[200]; memset(vis,0,sizeof(vis)); int i,k; for (i = 1;i <= n;i++) d[i] = G[1][i]; d[1] = 0; vis[1] = 1; int imin,xb = 1; for (i = 1;i < n;i++) { imin = MAX; for (k = 1;k <= n;k++) //以xb为起点↓ if (!vis[k] && d[xb] + G[xb][k] < d[k]) //最短的那条边,快到碗里来 d[k] = d[xb] + G[xb][k]; vis[xb] = 1; for (k = 1;k <= n;k++) if (!vis[k] && imin > d[k]) imin = d[xb = k]; //找到最小的点,并以此为起点找最短 vis[xb] = 1; } return d[n]; } int main() { int n,m; while (scanf ("%d%d",&n,&m),n || m) { int i,k; for (i = 0;i <= n;i++) for (k = 0;k <= n;k++) if (i == k) G[i][k] = 0; else G[i][k] = MAX; for (i = 0;i < m;i++) { int a,b,c; scanf ("%d%d%d",&a,&b,&c); if (c < G[a][b]) { G[a][b] = c; G[b][a] = c; } } int ans = djs(n,1); printf ("%d\n",ans); } return 0; }
贝尔曼福特
能够有负权边,就是不停的松弛,时间复杂度有点高
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 99999 #define qmin(a,b) a > b ? b : a //最短路 //贝尔曼福特 struct E { int e,v; int w; }e[10000]; int cont; int BF (int n,int s) { int d[200]; int i,k; for (i = 0;i <= n;i++) d[i] = MAX; d[s] = 0; for (i = 1;i < n;i++) //找n - 1条边 { for (k = 0;k < cont;k++) //把每条边都遍历一遍 { int a = e[k].e,b = e[k].v; d[b] = qmin (d[b],d[a] + e[k].w); //松弛 } } return d[n]; } int main() { int n,m; while (scanf ("%d%d",&n,&m),n || m) { int i,k; cont = 0; for (i = 0;i < m;i++) { int a,b,c; int tf = 1; scanf ("%d%d%d",&a,&b,&c); for (k = 0;k < cont;k++) if ((e[k].e == a && e[k].v == b) || (e[k].e == b && e[k].v == a)) if (e[k].w > c) { e[k].w = c; tf = 0; break; } if (tf) { //无向图 e[cont].e = a; e[cont].v = b; e[cont++].w = c; e[cont].e = b; e[cont].v = a; e[cont++].w=c; } } int ans = BF(n,1); printf ("%d\n",ans); } return 0; }
弗洛伊德
这简直就像暴力啊,时间复杂度大的夸张,可是求出了每两个点之间的最短路,对于数据多并且图小的题目还是能够考虑的。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 99999 #define qmin(a,b) a > b ? b : a //最短路 //弗洛伊德 int G[200][200]; int fld (int n,int s) { int d[200][200]; int i,j,k; memcpy(d,G,sizeof (G)); for (i = 0;i <= n;i++) for (k = 0;k <= n;k++) for (j = 0;j <= n;j++) d[k][j] = qmin (d[k][j],d[k][i] + d[i][j]); return d[s][n]; } int main() { int n,m; while (scanf ("%d%d",&n,&m),n || m) { int i,k; //邻接矩阵初始化 for (i = 0;i <= n;i++) for (k = 0;k <= n;k++) if (i == k) G[i][k] = 0; else G[i][k] = MAX; for (i = 0;i < m;i++) { int a,b,c; scanf ("%d%d%d",&a,&b,&c); if (G[a][b] > c) { G[a][b] = c; G[b][a] = c; } } int ans = fld(n,1); printf ("%d\n",ans); } return 0; }
SPFA
BF的队列优化,有点像BFS。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 99999 #define qmin(a,b) a > b ? b : a //最短路 //SPFA struct node { int v; int w; struct node *next; }head[10001]; int q[1000000]; //队列 int s = 0,e = 0; int SPFA (int n,int st) { bool inq[200]; //标记是否还在队列中(队列中的不在入队列) int d[200]; int i; memset (inq,0,sizeof (inq)); for (i = 0;i <= n;i++) d[i] = MAX; s = 0; e = 0; d[st] = 0; q[s++] = st; inq[st] = 1; //源点入队列并标记 while (s > e) { int now = q[e++]; inq[now] = 0; //出队列的就恢复标记 struct node *p = head[now].next; while (p != NULL) { if(d[p->v] > d[now] + p->w) //松弛成功 { d[p->v] = d[now] + p->w; if (!inq[p->v]) //假设在队列中就不入队列 { q[s++] = p->v; inq[p->v] = 1; } } p = p->next; } } return d[n]; //其它的和BF一样了 } int add (int a,int b,int c) //邻接链表 { struct node *t = new node; t->v = b; t->w = c; t->next = NULL; struct node *p = &head[a]; while (p->next != NULL) p = p->next; p->next = t; return 1; } int main() { int n,m; while (scanf ("%d%d",&n,&m),n || m) { memset(head,0,sizeof (head)); int i,k; for (i = 0;i < m;i++) { int a,b,c; int tf = 1; scanf ("%d%d%d",&a,&b,&c); add (a,b,c); add (b,a,c); } int ans = SPFA(n,1); printf ("%d\n",ans); } return 0; }
SPFA前向星版本号
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #define EGMAX 200000 #define DOMAX 2000 #define MAX 999999 using namespace std; struct node { int e; int w; int next; }eg[EGMAX]; int head[DOMAX]; int cont; void add(int s,int e,int w) { eg[cont].e = e; eg[cont].w = w; eg[cont].next = head[s]; head[s] = cont++; } int dis[DOMAX]; bool vis[DOMAX]; int SPFA(int s,int e,int n) { int now; queue<int> que; memset(vis,0,sizeof (vis)); for (int i = 0;i <= n;i++) dis[i] = MAX; vis[s] = 1; dis[s] = 0; que.push(s); while (!que.empty()) { now = que.front(); que.pop(); vis[now] = 0; for (int i = head[now];~i;i = eg[i].next) { if (dis[eg[i].e] > dis[now] + eg[i].w) { dis[eg[i].e] = dis[now] + eg[i].w; if (!vis[eg[i].e]) { vis[eg[i].e] = 1; que.push(eg[i].e); } } } } return dis[e]; } int main() { int n,m; while (~scanf ("%d%d",&n,&m) && (n || m)) { cont = 0; memset(head,-1,sizeof (head)); for(int i = 0;i < m;i++) { int s,e,w; scanf ("%d%d%d",&s,&e,&w); add(s,e,w); add(e,s,w); } int ans = SPFA(1,n,n); printf ("%d\n",ans); } return 0; }