以HDU 2544为例 将所有最短路的模板敲一遍
1、Dijkstra
思想:以边贪心+松弛
适用范围:单源最短路径、边权不能为负
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 0x7ffffff int n,m; int mpt[105][105]; int vis[105]; int dist[105]; void init() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j)mpt[i][j]=0; else mpt[i][j]=INF; } } } void dij() { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) dist[i]=mpt[1][i]; vis[1]=1; dist[1]=0; int v=1; for(int i=1;i<n;i++) { int mink=INF; for(int j=1;j<=n;j++) { if(vis[j]==0&&mink>dist[j]) { v=j; mink=dist[j]; } } if(mink==INF)break; vis[v]=1; for(int j=1;j<=n;j++) { if(vis[j]==0&&dist[j]>dist[v]+mpt[v][j]) dist[j]=dist[v]+mpt[v][j]; } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; init(); int a,b,c; for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); if(c<mpt[a][b]) { mpt[a][b]=c; mpt[b][a]=c; } } dij(); printf("%d\n",dist[n]); } return 0; }
思想:动态规划
适用范围:稠密图、边权可正可负
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 0x7ffffff int n,m; int mpt[105][105]; void init() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j)mpt[i][j]=0; else mpt[i][j]=INF; } } } void floyd() { for(int i=1;i<=n;i++)//中间节点 { for(int j=1;j<=n;j++) { for(int k=1;k<=n;k++) { if(mpt[j][k]>mpt[j][i]+mpt[i][k]) mpt[j][k]=mpt[j][i]+mpt[i][k]; } } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; init(); int a,b,c; for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); if(c<mpt[a][b]) { mpt[a][b]=c; mpt[b][a]=c; } } floyd(); printf("%d\n",mpt[1][n]); } return 0; }3、Bellman_Ford
思想:贪心松弛、Bellman-Ford算法的迭代松弛操作,实际上就是按顶点距离s的层次,逐层生成这棵最短路径树的过程
适用范围:普遍适用、但效率很低
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 0x7ffffff int n,m; struct node { int u,v,len; }edge[10005]; int dist[105]; bool Bellman_Ford() { for(int i=1;i<=n;i++) dist[i]=INF; dist[1]=0; for(int i=1;i<n;i++) { for(int j=1;j<=m*2;j++) { if(dist[edge[j].v] > dist[edge[j].u] + edge[j].len) //松弛(顺序一定不能反~) { dist[edge[j].v] = dist[edge[j].u] + edge[j].len; } } } bool flag=true; //判断是否有负环路 for(int i=1;i<=m*2;i++) { if(dist[edge[i].v]>dist[edge[i].u]+edge[i].len) { flag=false; break; } } return flag; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; int a,b,c; for(int i=1;i<=m*2;i++) { scanf("%d%d%d",&a,&b,&c); edge[i].u=a; edge[i].v=b; edge[i++].len=c; edge[i].u=b; edge[i].v=a; edge[i].len=c; } if(Bellman_Ford()) printf("%d\n",dist[n]); else printf("-1\n"); } return 0; }
思想:Bellman-Ford算法的优化、动态逼近法、用队列来保存待优化的节点、由无权图的BFS转化而来
适用范围:如果某个点进入队列次数超过N次则存在负环(SPFA无法处理带负环的图)/一般用邻接表来存储图
#include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; #define INF 0x7ffffff int n,m; struct node { int to,next,val; }edge[10005]; int head[105]; int dist[105]; int vis[105]; int k; void add(int x,int y,int val) { edge[k].to=y; edge[k].val=val; edge[k].next=head[x]; head[x]=k++; } void SPFA() { queue<int> q; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) dist[i]=INF; dist[1]=0; vis[1]=1; q.push(1); while(!q.empty()) { int now=q.front(); q.pop(); vis[now]=0; for(int i=head[now];i!=-1;i=edge[i].next) { int s=edge[i].to; if(dist[s]>dist[now]+edge[i].val) { dist[s]=dist[now]+edge[i].val; if(vis[s]==0) { vis[s]=1; q.push(s); } } } } } void init() { k=0; memset(head,-1,sizeof(head)); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; init(); int a,b,c; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } SPFA(); printf("%d\n",dist[n]); } return 0; }
一般不等式可以转化为图论的建图、最后求单源最长路径或最短路径