一.求最短路径
1.Dijkstra算法(不可以求负边)
//Dijkstra算法
const int INF=0x3f3f3f3f;
int cost[N][N]; //cost[u][v]表示e=(u,v)的权值
int d[N]; //定点s出发的最短距离
bool used[N]; //已经使用过的图
int n; //定点数
//求从s点出发到各个定点的最短路径
void Dijkstra(int s)
{
memset(d,INF,sizeof(d));
d[s]=0;
while(true)
{
int k=-1;
//从尚未使用过的顶点中选择一个距离最小的顶点
for(int i=0;i<n;i++)
{
if(!used[i]&&(k==-1||d[i]<d[k]))
k=i;
}
if(k==-1)
break;
used[k]=true;
for(int i=0;i<n;i++)
{
d[i]=min(d[i],d[k]+cost[k][i]);
}
}
}
2.Floyd_Warshall算法(可以求负边,但复杂度较高)
//Floyd-Warshall算法 复杂度n^3 可以计算负边
int d[N][N]; //d[u][v]表示e=(u,v)的权值(不存在时为INF,不过的d[i][i]=0)
int n; //顶点的个数
void warshall_floyd()
{
for(int k=0;i<n;i++)
{
for(int i=0;j<n;j++)
{
for(int j=0;k<n;k++)
{
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
3.Bellman_Ford算法(可以求负边)
//Bellman-Ford算法 (可以判断负环)
const int INF=0x3f3f3f3f;
//从顶点from指向to的权值为cost的边
struct edge
{
int from;
int cost;
int cost;
};
edge e[N]; //边
int d[N]; //最短距离
int n,E; //n是顶点数,E是边数
//求解从顶点s出发到所有点的最短距离
void short_path(int s)
{
memset(d,INF,sizeof(d));
d[s]=0;
while(true)
{
bool update=false;
for(int i=0;i<E;i++)
{
edge a=e[i];
if(d[a.from]!=INF&&d[a.to]>d[a.from]+a.cost)
{
d[a.to]=d[a.from]+a.cost;
}
}
if(!update)
break;
}
}
二.路径还原问题
Dijkstra 还原
//Dijkstra算法路径还原 求解最短路径的路径
int prev[N]; //最短路上的前趋顶点
int cost[N][N]; //cost[u][v]表示e=(u,v)的权值
int d[N]; //最短距离
bool used[N]; //已使用过的顶点
int n; //顶点个数
//求从起点s出发到各个顶点的最短距离
void Dijkstra(int s)
{
memset(d,INF,sizeof(d));
memset(prev,-1,sizeof(prev));
d[s]=0;
while(true)
{
int k=-1;
for(int i=0;i<n;i++)
{
if(!used[i]&&(k==-1||d[i]<d[k])
{
k=i;
}
}
if(k==-1)
break;
used[k]=true;
for(int i=0;i<n;i++)
{
if(d[k]+cost[k][i]<d[i])
{
d[i]=d[k]+cost[k][i];
prev[i]=k;
}
}
}
}
//到顶点t的最短路
vector<int> get_path(int t)
{
vector<int> path;
for(;t!=-1;t=prev[t])
path.push_back(t); //不断沿着prev[t]走到t=s;
//这样得到的是按着t到s的顺序,所以翻转之
reverse(path.begin(),path.end());
return path;
}
三.最小生成树
概念:给定一个无向图,如果它的某个子图中任意连个顶点都有一个互相联通并且是一颗数,那么这棵树就叫做生成树。如果边上有权值,那么使得边权和最小的生成树叫做最小生成树
1.prim算法
//Prim算法
//和Dijkstra 算法的思路类似
const int INF=0x3f3f3f3f;
int cost[N][N]; //cost[u][v]表示边e=(u,v)的权值
int n; //顶点个数
bool used[N]; // 顶点i是否包含在集合x中
int mincost[N]; //从集合x出发的边到每个顶点的最小权值
int prim()
{
memeset(mincost,INF,sizeof(mincost));
mincost[0]=0;
int res=0;
while(true)
{
int k=-1;
//从不属于x的顶点中选取从x到其权值最小的顶点
for(int i=0;i<n;i++)
{
if(!used[i]&&(k==-1||mincost[i]<mincost[k])
k=i;
}
if(k==-1)
break;
used[k]=true; //把顶点v加入x
res+=mincost[k]; //把边的长度加到结果中
for(int i=0;i<n;i++)
{
mincost[i]=min(mincost[i],cost[v][i]);
}
}
return res;
}