今天是我入队的第180天。不知道以后的路还有多长,但还是要坚持下去!
一直学习别人的东西,看别人的总结,这次我也想自己写一份总结,也算不辜负我这半年的付出。
最早接触的算法应该就是最短路了,整整半年了,现在终于有资本说自己还是懂那么一种算法的。
之前学的时候总想把dijkstra,bellman ford,spfa,floyd全都总结出来,但网上的资料很零散,所以就把这次的总结当做我对acm的一点贡献吧~(大神勿喷,我还只能算是一个算法入门者)
以下总结基本都以hdu2544为例
1.dijkstra 邻接矩阵形式
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
using namespace std;
const int INF= 1<<30;
const int MAX=1050;
int dis[MAX],n,m;
int edges[MAX][MAX];
int visit[MAX];
//最小下标为1
void dijkstra(int v)
{
int i,j;
int u;
memset(visit,0,sizeof(visit));//标记是否已求出最短路径
fill(dis+1,dis+n+1,INF);
dis[v]=0;
while(1) //最多循环n次就够了,每次找到 v到某一个点的最短路
{
u=-1;
for(j=1;j<=n;j++) //找当前最短
if((!visit[j])&&(u==-1||dis[j]<dis[u]))
u=j;
if(u==-1)
break;
visit[u]=1;
for(j=1;j<=n;j++) //更新当前所有的最短路径
if((!visit[j])&&(edges[u][j]<INF)&&(dis[u]+edges[u][j])<dis[j])
dis[j]=dis[u]+edges[u][j];
}
}
int main()
{
int i,j,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
for(i=0;i<MAX;i++) //矩阵初始化为INF
{
edges[i][i]=0;
for(j=i+1;j<MAX;j++)
{
edges[i][j]=INF;
edges[j][i]=INF;
}
}
for(i=0;i<m;i++) //获得各边之间的长度
{
scanf("%d%d%d",&a,&b,&c);
if(edges[a][b]>c)
{
edges[a][b]=c;
edges[b][a]=c;
}
}
dijkstra(1); //求以1为起点到各点的最短路径
printf("%d\n",dis[n]);
}
return 0;
}
2.dijkstra邻接表形式
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const double pi=4.0*atan(1.0);
const int MAX=105;
const int INF=1<<29;
struct Edge{
int v,val;
Edge(){}
Edge(int _v,int _val):v(_v),val(_val){}
};
vector<Edge> g[MAX];
int n;
int dis[MAX],vis[MAX];
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
fill(dis+1,dis+n+1,INF);
dis[s]=0;
while(1)
{
int u=-1;
for(int v=1;v<=n;v++)
if(!vis[v]&&(u==-1||dis[u]>dis[v]))
u=v;
if(u==-1)
break;
vis[u]=1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].v;
if(!vis[v]&&dis[v]>dis[u]+g[u][i].val)
dis[v]=dis[u]+g[u][i].val;
}
}
}
int main()
{
int i,j,k;
int m;
int x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
for(i=1;i<=n;i++)
g[i].clear();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
g[x].push_back(Edge(y,z));
g[y].push_back(Edge(x,z));
}
dijkstra(1);
printf("%d\n",dis[n]);
}
return 0;
}
3.dijkstra向前星
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
const double pi=4.0*atan(1.0);
const int MAXN=10005;
const int MAX=105;
const int INF=1<<29;
struct Edge{
int v,val;
int next;
};
Edge edge[MAXN<<1];
int n;
int head[MAX],total;
int dis[MAX],vis[MAX];
void init()
{
memset(head,-1,sizeof(head));
total=0;
}
void addedge(int x,int y,int z)
{
edge[total].v=y;
edge[total].val=z;
edge[total].next=head[x];
head[x]=total++;
}
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
fill(dis+1,dis+n+1,INF);
dis[s]=0;
while(1)
{
int u=-1;
for(int v=1;v<=n;v++)
if(!vis[v]&&(u==-1||dis[u]>dis[v]))
u=v;
if(u==-1)
break;
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!vis[v]&&dis[v]>dis[u]+edge[i].val)
dis[v]=dis[u]+edge[i].val;
}
}
}
int main()
{
int i,j,k;
int m;
int x,y,z;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
dijkstra(1);
printf("%d\n",dis[n]);
}
return 0;
}
4.dijkstra优先队列优化+邻接表形式
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=100005;
const int INF=9999999;
int flag[MAXN];
int dist[MAXN],n;
struct Node{
int id,val;
Node(){}
Node(int _id,int _val):id(_id),val(_val){}
bool operator<(const Node &a)const
{ //重载<,使优先队列队首始终是val最小的元素
return val > a.val;
}
};
struct Edge{
int v,cost;
Edge(){}
Edge(int _v,int _cost):v(_v),cost(_cost){}
};
vector<Edge>mp[MAXN]; //mp[i][j].v表示i的第j条边连接的是顶点v,权值为mp[i][j].cost
void dijkstra(int s)
{
int i,j,k,v,cost;
Node tep;
memset(flag,0,sizeof(flag));
for(i=0;i<10005;i++)
dist[i]=INF;
priority_queue<Node> que;
dist[s] = 0;
que.push(Node(s,0)); //起点入队
while(!que.empty())
{
tep = que.top();
que.pop();
if(flag[tep.id])
continue; //如果tep.id已经在集合中,不用拿出
flag[tep.id] = 1; //将tep.id放入集合
for(i = 0;i < mp[tep.id].size(); i++)
{
v = mp[tep.id][i].v;
cost = mp[tep.id][i].cost;
if(!flag[v] && dist[v] > dist[tep.id] + cost)
{ //松弛
dist[v] = dist[tep.id] + cost;
que.push(Node(v,dist[v])); //加入集合
}
}
}
}
int main()
{
int i,j,k,m,T;
int u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
for(i = 1;i <= n; i++)
mp[i].clear();
for(i = 1;i <= m;i++)
{
scanf("%d%d%d",&u,&v,&w);
mp[v].push_back(Edge(u,w)); //双向边
mp[u].push_back(Edge(v,w));
}
dijkstra(1);
printf("%d\n",dist[n]);
}
return 0;
}
5.dijkstra优先队列优化+邻接矩阵
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAX=105;
const int INF=9999999;
struct Node{
int id,val;
Node(){}
Node(int _id,int _val):id(_id),val(_val){}
bool operator<(const Node &a)const
{ //重载<,使优先队列队首始终是val最小的元素
return val > a.val;
}
};
int flag[MAX];
int dist[MAX],n,m;
int edges[MAX][MAX];
void dijkstra(int s)
{
int i,j,k,v,cost;
Node tep;
memset(flag,0,sizeof(flag));
for(i=0;i<MAX;i++)
dist[i]=INF;
priority_queue<Node> que;
dist[s] = 0;
que.push(Node(s,0)); //起点入队
while(!que.empty())
{
tep = que.top();
que.pop();
if(flag[tep.id])
continue; //如果tep.id已经在集合中,不用拿出
flag[tep.id] = 1; //将tep.id放入集合
for(i = 1;i <= n; i++)
{
v = i;
cost = edges[tep.id][i];
if(!flag[v] &&cost<INF&& dist[v] > dist[tep.id] + cost)
{ //松弛
dist[v] = dist[tep.id] + cost;
que.push(Node(v,dist[v])); //加入集合
}
}
}
}
int main()
{
int i,j,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
for(i=0;i<MAX;i++) //矩阵初始化为INF
{
for(j=0;j<MAX;j++)
{
if(i==j)
edges[i][j]=0;
else
edges[i][j]=INF;
}
}
for(i=0;i<m;i++) //获得各边之间的长度
{
scanf("%d%d%d",&a,&b,&c);
if(edges[a][b]>c)
{
edges[a][b]=c;
edges[b][a]=c;
}
}
dijkstra(1); //求以1为起点到各点的最短路径
printf("%d\n",dist[n]);
}
return 0;
}
6.bellman ford
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
const int INF= 99999999;
const int MAX= 1010;
typedef struct Edge //边
{
int u;
int v;
int cost;
}Edge;
Edge edge[100000];
int dis[MAX], pre[MAX];
//最小下标为1
//点, 边, 起点
bool Bellman_Ford(int nodenum,int edgenum,int original) //有向图的最短路
{
for(int i = 1; i <= nodenum; ++i) //初始化
dis[i] = INF;
dis[original]=0;
for(int i = 0; i < nodenum - 1; i++) //总循环 点数-1 次
for(int j = 1; j <= edgenum; j++) //每条边松弛
if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
{
dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
pre[edge[j].v] = edge[j].u;
}
bool flag = 1; //判断是否含有负权回路
for(int i = 1; i <= edgenum; ++i)
if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
{
flag = 0;
break;
}
return flag;
}
void print_path(int root) //打印最短路的路径(反向)
{
while(root != pre[root]) //前驱
{
printf("%d-->", root);
root = pre[root];
}
if(root == pre[root])
printf("%d\n", root);
}
int main()
{
int i,j;
int N,M;
int a,b,c;
while(scanf("%d%d",&N,&M)!=EOF)
{
if(N==0&&M==0)
return 0;
for(i=0;i<100000;i++)
{
edge[i].cost=INF;
edge[i].u=edge[i].v=0;
}
j=1;
for(i=0;i<M;i++)
{
scanf("%d%d%d",&a,&b,&c);
edge[j].u=a;
edge[j].v=b;
edge[j++].cost=c;
edge[j].u=b;
edge[j].v=a;
edge[j++].cost=c;
}
Bellman_Ford(N,M*2,1);
printf("%d\n",dis[N]);
}
return 0;
}
7.spfa链表
注意这个模板求的是最长路,相信你自己可以改成最短路的
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include<map>
#include<stack>
#include<vector>
using namespace std;
const int MAX= 110;
int n,m;
struct Edge{
int v,cost;
Edge(){}
Edge(int _v,int _cost):v(_v),cost(_cost){}
};
vector<Edge> edge[110];
int dis[MAX], pre[MAX];
int v[MAX];
int visit[MAX];
void spfa(int s)
{
queue<int> k;
int i,h;
for(i=1;i<=n+1;i++)
{
dis[i]=-5000;
visit[i]=0;
}
k.push(s);
dis[s]=0;
visit[s]=1;
while(!k.empty())
{
h=k.front();
k.pop();
visit[h]=0;
for(i=0;i<edge[h].size();i++)
{
if(dis[h]+edge[h][i].cost>dis[edge[h][i].v])
{
dis[edge[h][i].v]=dis[h]+edge[h][i].cost;
pre[edge[h][i].v]=h;
if(!visit[edge[h][i].v])
{
k.push(edge[h][i].v);
visit[edge[h][i].v]=1;
}
}
}
}
}
void print_path(int root) //打印最短路的路径(反向)
{
stack<int> st;
while(!st.empty())
st.pop();
while(root != pre[root]) //前驱
{
st.push(root);
root = pre[root];
}
if(root == pre[root])
st.push(root);
printf("circuit : ");
while(!st.empty())
{
if(st.top()==n+1)
{
printf("1\n");
break;
}
else
printf("%d->",st.top());
st.pop();
}
}
int main()
{
int i,j,k;
int a,b,c;
int T;
int cas=1;
while(scanf("%d",&T)!=EOF)
{
cas=1;
while(cas<=T)
{
if(cas!=1)
printf("\n");
scanf("%d",&n);
for(i=1;i<=n+1;i++)
edge[i].clear();
for(i=1;i<=n;i++)
scanf("%d",v+i);
v[n+1]=0;
for(i=0;i<=n+1;i++)
pre[i]=i;
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
edge[a].push_back(Edge(b,v[b]));
}
spfa(1);
printf("CASE %d#\n",cas++);
printf("points : %d\n",dis[n+1]);
print_path(n+1);
}
}
return 0;
}
8.spfa邻接矩阵
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
const int INF= 99999999;
const int MAX= 1010;
int n,m,edges[MAX][MAX];
int visit[MAX];
int dis[MAX];
void spfa(int s)
{
queue<int> k;
int i,h;
for(i=1;i<=n;i++)
{
dis[i]=INF;
visit[i]=0;
}
k.push(s);
dis[s]=0;
visit[s]=1;
while(!k.empty())
{
h=k.front();
k.pop();
visit[h]=0;
for(i=1;i<=n;i++)
{
if(edges[h][i]<INF&&dis[h]+edges[h][i]<dis[i])
{
dis[i]=dis[h]+edges[h][i];
if(!visit[i])
{
k.push(i);
visit[i]=1;
}
}
}
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
for(i=0;i<=n;i++) //矩阵初始化为INF
{
for(j=0;j<=n;j++)
{
if(i==j)
edges[i][j]=0;
else
edges[i][j]=INF;
}
}
int a,b,c;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(edges[a][b]>c)
{
edges[a][b]=c;
edges[b][a]=c;
}
}
spfa(1);
printf("%d\n",dis[n]);
}
return 0;
}
9.floyd
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int INF= 999999999;
const int N=1005;
int n,m;
int edges[N][N];
//最小下标为 1
void floyd() //Floyd算法
{
int i, j, k;
//最外层 节点个数次 循环
for(k = 1; k <= n; k++) //k为中间点
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if(edges[i][k]!=INF&&edges[k][j]!=INF)
if(edges[i][k] + edges[k][j] < edges[i][j])
edges[i][j] = edges[i][k] + edges[k][j];
}
int main()
{
int i,j,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
return 0;
for(i=0;i<N;i++) //矩阵初始化为INF
{
edges[i][i]=0;
for(j=i+1;j<N;j++)
{
edges[i][j]=INF;
edges[j][i]=INF;
}
}
for(i=0;i<m;i++) //获得各边之间的长度
{
scanf("%d%d%d",&a,&b,&c);
if(edges[a][b]>c)
{
edges[a][b]=c;
edges[b][a]=c;
}
}
floyd();
printf("%d\n",edges[1][n]);
}
return 0;
}
没什么注释,希望能对你们学最短路有帮助~