图论基本算法打卡


Kruskal

#include<iostream>
#include<algorithm>
using namespace std;

const int N =1e5+10,M = 2e5+10,INF=0x3f3f3f3f;
int n,m;
int p[N],dist[N];

struct Edge
{
    int a,b,w;
    
    bool operator< (const Edge & W)const
    {
        return w<W.w;
    }
}edges[M];
//并查集
int find(int x)
{
    //记忆口诀:只用一次x 父亲等于祖宗
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
    
}
int kruskal()
{
    //先排个序
    sort(edges,edges+m);
    //初始化并查集
    for(int i=1;i<=n;i++) p[i]=i;
    
    int res=0,cnt=0;//res 表示距离 cnt表示加入边的条数
    //遍历每条边
    for(int i=0;i<m;i++)
    {
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;
        //判断a,b是否在同样一个集合
        a=find(a),b=find(b);
        //如果不在一个集合则合并,a插入到b
        if(a!=b)
        {
            p[a]=b;
            res+=w;
            cnt++;
        }
    }    
    //如果加入的边小于n-1则不能构成最小生成树
    if(cnt <n-1) return INF;
    return res;
}
int main()
{
    cin >> n >> m;
    for(int i=0;i<m;i++)
    {
        int a,b,w;
        cin >> a>>b>>w;
        edges[i]={a,b,w};
    }
    
    int t = kruskal();
    
    if(t>=INF) cout << "impossible";
    else cout << t;
    
    return 0;
}

Prim

#include<iostream>
#include<cstring>
using namespace std;

const int N =510,INF=0x3f3f3f3f;

int n,m;
int g[N][N],dist[N];
bool st[N];


int prim()
{
    //把所有距离初始话为0
    memset(dist,0x3f,sizeof dist);
    
    int res=0; //res表示总距离
    //遍历n次
    for(int i=0;i<n;i++)
    {
        //找到离集合最近的点
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j] && (t==-1 || dist[j] <dist[t]) )
                t=j;
        //判断这个点是否可达
        if(i && dist[t]==INF) return INF;
        //把这个点加入到集合
        st[t]=true;
        //先把这个点的距离加入总距离
        if(i) res+=dist[t];
        //用这个点跟新其他点
        for(int j=1;j<=n;j++) dist[j]=min(dist[j],g[t][j]);
    }
    return res;
}

int main()
{
    
    cin >> n >> m;
    memset(g,0x3f,sizeof g);
    while(m--)
    {
        int a,b,c;
        cin >> a >> b >> c;
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
    
    int res=prim();
    
    if(res==INF) puts("impossible");
    else cout << res;
    
    return 0;
}

bellman-ford

#include<iostream>
#include<cstring>
using namespace std;

const int N =510,M=1e4+10;

struct Edge
{
    int a,b,c;
} edges[M];

int n,m,k;
int dist[N];
int last[N]; //上一次的距离

void bellman_ford()
{
    //初始化距离 到起点的距离
    memset(dist,0x3f,sizeof dist);
    //第一个点到自己的距离为0
    dist[1]=0;
    //循环k次
    for(int i=0;i<k;i++)
    {
        //每次都要用上一次的距离比较
        memcpy(last,dist,sizeof dist);
        //遍历每一条遍
        for(int j=0;j<m;j++)
        {
            auto t = edges[j];
            dist[t.b]=min(dist[t.b],last[t.a]+t.c);
        }
    }
}
int main()
{
    cin >> n >> m >> k;
    
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin >> a >> b >>c;
        edges[i]={a,b,c};
    }
    
    bellman_ford();
    
    if (dist[n] > 0x3f3f3f3f / 2) puts("impossible");
    else printf("%d\n", dist[n]);
    return 0;
}

Dijkstra优先队列优化

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>

using namespace std;
typedef pair<int,int> PII;

const int N= 1.5e5+5,M=N*2;

int h[N],e[M],ne[M],idx,w[M];
int dist[N]; 
int n,m;
bool st[N];

void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int dijkstra()
{
    //初始化距离 表示到起点的距离
    memset(dist,0x3f,sizeof dist);
    //创建一个有限队列 目的是快速找出最小的点
    priority_queue<PII,vector<PII>,greater<PII>> heap;
    //第一个点到自己距离为0
    dist[1]=0;
    //把第一个点加入队列中去
    heap.push({0,1});
    //当队列不为空一直循环
    while(heap.size())
    {
        //取出最小元素
        auto t = heap.top();
        heap.pop();
        
        int ver=t.second; //ver 为最小元素的编号
        if(st[ver]) continue; //因为会产生冗余 所以要排除重复点
        st[ver]=true;
        //用最小的点跟新其他点的距离
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[ver]+w[i]) 
            {
                dist[j]=dist[ver]+w[i];
                heap.push({dist[j],j});
            }
        }
    }
    
    if(dist[n]>0x3f3f3f3f/2) return -1;
    return dist[n];
} 
int main()
{
    cin >> n >> m;
    memset(h,-1,sizeof h);
    
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cin >> a >> b >> c;
        add(a,b,c);
    }
    
    cout << dijkstra();
    
    return 0;
}

Dijkstra

#include<iostream>
#include<cstring>

using namespace std;

const int N = 510;

int n,m;
int g[N][N],dist[N];
bool st[N];


void dijkstra()
{
    //初始化
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    //循环n次
    for(int i=1;i<=n;i++)
    {
        //找到最小点
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j] && (t==-1 || dist[j]<dist[t]))
                t=j;
        
        
        //用最小点跟新其他点
        for(int j=1;j<=n;j++)
        {
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        }
        
        st[t]=true;
    }
    
}
int main()
{
    cin >> n >> m;
    memset(g,0x3f,sizeof g);
    while(m--)
    {
        int a,b,c;
        cin >> a >> b >> c;
        g[a][b]=min(g[a][b],c);
    }
    
    dijkstra();
    
    if(dist[n]>0x3f3f3f3f/2) puts("-1");
    else cout << dist[n];
    
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值