自己码的图论板子(实时更新)

这篇博客记录了作者自己编写的图论算法板子,包括链式前向星、Floyd算法、Prim算法、Kruskal、Dijkstra、并查集、费用流等,并不断进行实时更新和优化。详细介绍了各种算法的实现细节和适用场景。
摘要由CSDN通过智能技术生成

自己码的图论板子(实时更新)

更新日志

2020.8.15 上传了 链式前向星,Floyd算法,Prim算法, 并查集,Kruskal,Dijkstra,BellmanFord算法,spfa,dp求树的直径,bfs求分层图,匈牙利算法,欧拉路,倍增LCA,Tarjan,Dinic,费用流,线段树,树链剖分
2020.8.17 小幅度改动了Kruskal和并查集的算法
2020.8.18 用struct中置函数优化了并查集
2020.8.19 用struct中放置函数又花了线段树,树链剖分,更改kru中使用并查集部分,更改了树链剖分的部分命名,对每条边的信息追加了起点u
2020.8.20 修复了费用流的bug

约定

不再对标有废弃的板子更新,但是此板子为正确且可套用的,只是出现了上级取代而已
一个图的点数为n,一个图的边数为m
边的具体信息通过 edge储存
一条边的起点为u,终点为v,权值信息为c
遍历边起点为x,终点为y
到点的距离通过 dis储存
分层图信息通过 d 储存
时间戳信息通过 dfn 储存
一个点是否被使用用used 一条边是否被使用用usedWay
需要建立反向图的情况在信息后面全部加2,如edge2,search2
根节点信息用 root ,源点用S,汇点用T
临时变量用tmp,临时队列用que,临时栈用s
涉及具体数据结构遍历名称随单词拼接大写
于栈中用 ins,于队列中用 inque
点的度为deg ,出度为outdeg 入度为indeg

前置内容

#define MAXN 25000//点数
#define MAXM (2*MAXN)//道路数
//#define int long long 
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
#define dis(i,j)  (sqrt(pow((nod[i].x-nod[j].x),2)+pow((nod[i].y-nod[j].y),2)))
struct {
    double x,y;
}nod[MAXN];//用于点以坐标表示的时候

链式前向星

#define search(i,y) for(int i=head[y];i;i=edge[i].next) //遍历一个点的出边
#define add(u,v,c)  {edge[++cnt]={u,v,c,head[u]};head[u]=cnt;}//加入一条边
int head[MAXN],cnt=1;//0说明没有下一个值
struct EDGE{
    int u,v,c;
    int next;//下一个值的位置;
}edge[MAXM];

Floyd算法

//floyd算法求任意两点之间的最短距离
//因为floyd求的一般都是稠密图,储存方式邻接矩阵
//floyd也可以用来在点数较小的情况下求区间闭包和可达性

int edge[MAXN][MAXN];      //邻接矩阵
int dis[MAXN][MAXN];
void Floyd(int n){// 编号从1 开始
    memcpy(dis,edge,sizeof(edge));
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}

Prim算法

//从点的角度求最小生成树,复杂度为O(N^2),储存方式邻接矩阵
//在稠密图中效果优于kru,稀疏图中劣于kru
//可以用二叉堆优化到O(M+N)但是涉及到边了不如直接上kru

int edge[MAXN][MAXN];//邻接矩阵存边
bool used[MAXN]={0};
int d[MAXN];
int Prim(int n){
    memset(d,inf,sizeof(d));
    memset(used,0,sizeof(used));
    d[1]=0;
    for(int i=1;i<n;i++){                     //一共只需要进行n-1次操作
        int x=0;
        for(int j=1;j<=n;j++)
            if(!used[j]&&(x==0||d[x]>d[j]))   //遍历找出没有用过并且距离已选遍最近的点
                x=j;
        used[x]= true;
        for(int y=1;y<=n;y++)
            if(!used[y])d[y]=min(d[y],edge[x][y]);
    }
    int  ans=0;
    for(int i=1;i<=n;i++){
        ans+=d[i];
        if(ans>=inf)return -1;//图不连通则返回-1
    }
    return ans;
}

并查集

struct DisjointSet {
    int n;
    int root[MAXN];
    void init(int x){
        n=x;
        for(int i=1;i<=n;i++)root[i]=i;
    }
    int find(int x){
        if(x!=root[x])
            root[x]=find(root[x]);
        return root[x];
    }
    void merge(int x,int y){root[find(x)]=find(y);}//将x合并到y中}
    bool judge(int x,int y){return find(x)==find(y);}
}grp;

Kruskal

//Kruskal算法 从边的角度算最小生成树
//复杂度为O(m) 需要并查集作为辅助
typedef  pair<int,pair<int ,int > > pi_ii;
int n;
vector<pair<int,pair<int,int> > > edge;
int  kruskal(int m){//m为边数
    int ans=0;
    grp.init(n);
    priority_queue<pi_ii ,vector<pi_ii>,greater<pi_ii > > que;
    for(auto i:edge)
        que.push(i);
    while(!que.empty()){
        pi_ii tmp;
        tmp=que.top();que.pop();
        int u=tmp.second.first,v=tmp.second.second;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值