月球美容计划之最短路
那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; }