图论常用算法

#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的节点,把和它相邻的节点入队,删除与节点相邻的边
//
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hi 姚辰辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值