#include<iostream>
using namespace std;
int n,m,k1;
int g[205][205];
int x,y,len;
int cx,cy;
const int INF=1e9;
//弗洛伊德算法
//求多源最短路径,可求带负值路径的最短路,但不能求负值环路,负值环路无最短路径
//初始最短路径为两点之间直达的距离
//现枚举一个中间点,点A经中间点到B的距离是否会小于直达的距离,如果小于就更新
//最后求得所有点到所有点的最短路径
int main(){
cin>>n>>m>>k1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){ //使用邻接矩阵存储图
if(i==j)
g[i][j]=0;
else
g[i][j]=INF;
}
for(int i=0;i<m;i++){
cin>>x>>y>>len;
g[x][y]=min(g[x][y],len);//由于图中可能存在自环和重边,存储边长时选择一个最短的存即可
}
for(int k=1;k<=n;k++) //三层for循环是弗洛伊德的主算法
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
g[i][j]=min(g[i][j],g[i][k]+g[k][j]); //更新两点之间直达的距离,和经过中间点中转的距离最小值
}
for(int i=0;i<k1;i++){
cin>>cx>>cy;
if(g[cx][cy]>INF/2)
cout<<"impossible"<<endl; //输出结果
else
cout<<g[cx][cy]<<endl;
}
return 0;
}
#include<iostream>
using namespace std;
int g[505][505];
int dist[505];
int visited[505];
int m,n;
int x,y,len;
const int INF=1e9;
//dijkstra算法
//求单源最短路径,要求边权值大于0,且不能有负环
//需要g[][]邻接矩阵存储图及边权值
//dist数组存储最短路径
//visited数组存储是否访问过该节点
//首先对上述数组初始化,dist[1]=0,其余为无穷大
//首先遍历一遍dist数组,找到一个最小值,记录下最小值和最小值所对应的节点
//更新与该节点相连的节点的dist值,如果dist[i]>dist[min]+g[min][i];则更新
//对上述操作循环遍历n次直到找到所有的节点
//输出dist[n]
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) //初始化邻接矩阵
for(int j=1;j<=n;j++){
if(i==j) g[i][j]=0;
else g[i][j]=INF;
}
for(int i=1;i<=n;i++) //初始化dist数组
dist[i]=INF;
dist[1]=0; //起始点dist距离为0
for(int i=1;i<=n;i++) //初始化visited数组
visited[i]=0;
for(int i=0;i<m;i++){
cin>>x>>y>>len;
g[x][y]=min(g[x][y],len);
}
for(int i=1;i<=n;i++){ //循环n次,直到找到n个点的最短路径
int minpre=INF;
int minN=0;
for(int j=1;j<=n;j++){ //找到dist数组中,未被访问的最小值
if(visited[j]==0&&dist[j]<=minpre){
minpre=dist[j];
minN=j;
}
}
//cout<<"min:"<<minN<<endl;
visited[minN]=1;
for(int j=1;j<=n;j++){ //更新与刚刚找到的最小值点相连的dist值,如果dist[j]>dist[minN]+g[minN][j],则更新
if(g[minN][j]!=INF && dist[j]>dist[minN]+g[minN][j])
dist[j]=dist[minN]+g[minN][j];
}
}
if(dist[n]!=INF)
cout<<dist[n]<<endl;
else
cout<<"-1"<<endl;
//cout<<dist[n]<<endl;
}
//普利姆算法,主要看一下和dijkstra的区别
//与dijkstra的相同点,同是贪心思想,每次都选择dist数组中最小的那个点,以这个点为基础更新其他点的最短路径,直至结束
//与dijkstra的不同点,dijkstar算法是计算起点到源点的最短路径,所以算法起始点必须是起点,当visited遍历到终点即可结束
//普利姆算法是最小生成树,visited必须遍历全部节点才能结束,而且起始点可以任意选一个,一般是选择编号为1的点
//求最小生成树一般是无向图,所以邻接矩阵是对称的,一条边需要存两次
#include<iostream>
using namespace std;
int g[505][505];
int dist[505];
int visited[505];
int pre[505]; //边集
int m,n;
int x,y,len;
int rSum; //结果,边的权值和
const int INF=0x3f3f3f3f;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) //初始化邻接矩阵
for(int j=1;j<=n;j++){
if(i==j) g[i][j]=INF;
else g[i][j]=INF;
}
for(int i=1;i<=n;i++)
dist[i]=INF;
dist[1]=0;
for(int i=1;i<=n;i++)
visited[i]=0;
for(int i=0;i<m;i++){
cin>>x>>y>>len;
g[x][y]=min(g[x][y],len); //边存两次
g[y][x]=min(g[x][y],len);
}
for(int i=1;i<=n;i++){
int minpre=INF;
int minN=0;
for(int j=1;j<=n;j++){
if(visited[j]==0&&dist[j]<=minpre){//贪心思想,每次找到一个dist数组中未被访问的最小节点
minpre=dist[j];
minN=j;
}
}
if(dist[minN]==INF) { //若找到的是孤立点,则不能构成一颗完整的树,直接返回
cout<<"impossible"<<endl;
return 0;
}
rSum=rSum+dist[minN]; //否则计算累计和
visited[minN]=1;
for(int j=1;j<=n;j++){ //更新找到的那个节点到所有节点的dist
if(visited[j]==0 && g[minN][j]!=INF && dist[j]>g[minN][j])//与dijkstra区别,dist是到已选择集合的最小值,而dijkstra是到源点,所以由dist[j]>dist[minN]+g[minN][j]改为>g[minN][j]
dist[j]=g[minN][j];
}
}
cout<<rSum<<endl; //返回最小生成树的权值和
//cout<<dist[n]<<endl;
}
//add
//判断一个图是否连通,以及图的连通分量,三种方法(深搜,广搜,并查集)
//使用一个数组visited标记节点是否被访问过,如果没有访问过,就调用深搜访问,并cnt++,直到所有节点都访问过一次。cnt即为连通分量
//判断一个图是否存在环路(深搜,拓扑排序)
//使用一个数组visited标记节点是否被访问过,对图进行深搜,如果遇到一个已访问过的节点则存在环,否则将该节点visited数组置为1标记已访问
//哈夫曼树
//将树存为一个小顶堆,每次输出两个最小值,将两个最小值相加并插入堆,并重新调整为一个小顶堆,直到堆中剩下最后一个元素
//拓扑排序
//选择一个入度为0的节点,把和它相邻的节点入队,删除与节点相邻的边
//
图论常用算法
最新推荐文章于 2025-08-15 09:45:14 发布