首页 > 编程语言 >算法基础模板整理(基础图论篇)

算法基础模板整理(基础图论篇)

时间:2023-04-14 13:34:35浏览次数:35  
标签:图论 dist int 基础 st low return true 模板

拓扑排序

bool topo(){
    queue<int> q;
    for(int u = 1; u <= n; u ++ )
        if(!ind[u]) q.push(u);
    
    int cnt = 0;
    while(!q.empty()){
        int u = q.front();
        q.pop();
        cnt ++ ;
        ans.push_back(u);
        for(int i = h[u]; i != -1; i = ne[i]){
            int v = e[i];
            if(!(--ind[v])) q.push(v);
        }
    }
    
    return cnt == n;
}


最短路

朴素Dijkstra

int dijkstra(){
    memset(dist, 0x3f, sizeof(dist));  dist[1] = 0;

    //循环n次 将n个点都加入最短路径网络(树)
    for(int i = 0; i < n; i ++ ){
        int t = -1;   //找到网络外距离源点最近的点
        for(int v = 1; v <= n; v ++ )
            if(!st[v] && (t == -1 || dist[v] < dist[t]))
                t = v;

        st[t] = true;   //加入最短路径网络 作为扩展点

        for(int j = h[t]; j != -1; j = ne[j]){
            int to = e[j], c = w[j];   
            if(!st[to]) dist[to] = min(dist[to], dist[t] + c);
        }
    }

    return dist[n] == inf ? -1 : dist[n];
}

堆优化Dijkstra

int dijkstra(){
    memset(dist, 0x3f, sizeof(dist));   dist[1] = 0;
    priority_queue<pii,vector<pii>,greater<pii>> q;  q.push({0, 1});    
    while(!q.empty()){
        auto [d, t] = q.top();
        q.pop();

        if(st[t]) continue;   //有的点可能被重复加入
        st[t] = true;

        for(int i = h[t]; i != -1; i = ne[i]){
            int v = e[i], c = w[i];
            if(dist[v] > d + c){
                dist[v] = d + c;
                q.push({dist[v], v});
            }
        }
    }
    return dist[n] == inf ? -1 : dist[n];
}


SPFA

int spfa(){
    memset(dist, 0x3f, sizeof(dist));
    queue<int> q; q.push(1);
    dist[1] = 0, st[1] = true;

    while(!q.empty()){
        int t = q.front();
        q.pop();

        st[t] = false;  //重新标记为false 之后有可能再次入队

        for(int i = h[t]; i != -1; i = ne[i]){
            int v = e[i], c = w[i];
            if(dist[v] > dist[t] + c){
                dist[v] = dist[t] + c;
                if(!st[v]) q.push(v), st[v] = true;
            }
        }
    }
    return dist[n];
}

SPFA判断负环

int spfa(){
    queue<int> q;
    for(int i = 1; i <= n; i ++ ) q.push(i), st[i] = true;//所有点放入点集

    //只遍历已经更新过距离的点,避免Bellman_Ford中每次遍历所有边的情况
    while(!q.empty()){
        int t = q.front();
        q.pop();

        st[t] = false;    //重新标记为false 之后有可能再次入队

        for(int i = h[t]; i != -1; i = ne[i]){
            int v = e[i], c = w[i];
            if(dist[v] > dist[t] + c){
                dist[v] = dist[t] + c;
                cnt[v] = cnt[t] + 1;          //记录cnt
                if(cnt[v] >= n) return true;  //存在负环

                if(!st[v]) q.push(v), st[v] = true;
            }
        }
    }
    return false;
}

SPFA SLF优化

void spfa(){
    memset(dist, 0x3f, sizeof(dist));
    deque<int> q; q.push_back(src);
    st[src] = true, dist[src] = 0;

    while(!q.empty()){
        ...
        //SLF优化
        for(int i = h[t]; i != -1; i = ne[i])
            ...
                    if(!q.empty() && dist[v] < dist[q.front()]) 
q.push_front(v);
                    else q.push_back(v);
                    st[v] = true;
            ...
        }
    }
}

Floyd

void init(){
    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= n; j ++ )
            if(i == j) continue;
            else dist[i][j] = inf;
}

void floyd(){
    for(int k = 1; k <= n; k ++ )
        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= n; j ++ )
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}



最小生成树

Prim

int prim(){
    memset(dist, 0x3f, sizeof(dist));
    int ans = 0;
    for(int i = 0; i < n; i ++ ){
        int t = -1;    //集合外最近的点作为扩展点
        for(int v = 1; v <= n; v ++ )
            if(!st[v] && (t == -1 || dist[v] < dist[t]))
                t = v;

        if(i && dist[t] == inf) return inf;  //不存在最小生成树
        if(i) ans += dist[t];

        st[t] = true;

        for(int v = 1; v <= n; v ++ )
            dist[v] = min(dist[v], g[t][v]);
    }
    return ans;
}

Kruskal

struct edge{
    int u, v, w;
}e[M];
int fa[N], n, m, cnt, ans;

int find(int x){
    return fa[x] == x ? x : (fa[x] = find(fa[x]));
}

int kruskal(){
    for(int i = 1; i <= n; i ++ ) fa[i] = i;
    sort(e + 1, e + m + 1, [](struct edge &a, struct edge &b){
        return a.w < b.w;
    });

    for(int i = 1; i <= m; i ++ ){
        int fu = find(e[i].u), fv = find(e[i].v);
        if(fu == fv) continue;    //在同一个集合中 会形成环
        fa[fv] = fu;
        ans += e[i].w;
        cnt ++ ;
    }

    if (cnt < n - 1) return inf;
    return ans;
}


Tarjan

Tarjan求LCA

void tarjan(int u){
    st[u] = 1;
    for(int i = h[u]; i != -1; i = ne[i]){
        int v = e[i];
        if(!st[v]){
            tarjan(v);
            fa[v] = u;
        }
    }

    for(auto [v, id] : query[u]){
        if(st[v]){
            int anc = find(v);    //最近公共祖先  find和并查集一样
            if(anc == u) res[id] = 1;   
            else if(anc == v) res[id] = 2;
            else res[id] = 0;
        }
    }
}

Tarjan求树上两点最近距离

//深搜求出节点到根节点的距离
void dfs(int u, int fa){
    for(int i = h[u]; i != -1; i = ne[i]){
        int v = e[i];
        if(fa == v) continue;
        dist[v] = dist[u] + w[i];   
        dfs(v, u);
    }
}

void tarjan(int u){
    st[u] = true;
...
    for(auto [v, id] : query[u]){
        if(st[v]){
            int anc = find(v);  //如果被访问过 那么LCA为find(v)
            res[id] = dist[u] + dist[v] - 2 * dist[anc];  
            //两点距离为两点到根节点的距离和减去两倍的LCA根节点的距离
        }
    }
}

Tarjan判断割边

void tarjan(int u, int in_edge){
    dfn[u] = low[u] = ++ num;
    st[ ++ top] = u;
    for(int i = h[u]; i != -1; i = ne[i]){
        int v = e[i];
        if(!dfn[v]){
            tarjan(v, i);                  //自底向上
            low[u] = min(low[u], low[v]);  //更新当前节点的最小时间戳
            if(low[v] > dfn[u])         //无法回退到u
                bridge[i] = bridge[i ^ 1] = true;  //割边
        }else if(i != (in_edge ^ 1))
            low[u] = min(low[u], dfn[v]);   //处理回退边
    }
    
    if(dfn[u] == low[u]){  //双连通分量起点u
        dcc_cnt ++ ; int v;
        do{ v = st[top -- ];   id[v] = dcc_cnt;   //割边
        }while(v != u);
    }
}

int ans(){
for(int i = 0; i < idx; i ++ ) if(bridge[i]) d[id[e[i]]] ++ ;   
//边i为割边 那么两边度数 + 1
for(int i = 1; i <= dcc_cnt; i ++ ) if(d[i] == 1) cnt ++ ;  
return (cnt + 1) / 2;
}

Tarjan判断割点

void tarjan(int u, int in_edge){
    dfn[u] = low[u] = ++ num;
    int flag = 0;
    for(int i = h[u]; i != -1; i = ne[i]){
        int v = e[i];
        if(!dfn[v]){
            tarjan(v, i);                  //自底向上
            low[u] = min(low[u], low[v]);  //更新当前节点的最小时间戳
            if(low[v] >= dfn[u]){        
                flag ++ ;
                if(u != root || flag > 1) cut[u] = true;
            }
        }else low[u] = min(low[u], dfn[v]);
    }
}


二分图

染色法判定二分图

bool dfs(int u, int c){
    color[u] = c;
    for(int i = h[u]; i != -1; i = ne[i]){
        int v = e[i];
        if(!color[v]){  //如果没有被染过色
            if(!dfs(v, 3 - c)) return false;  //自底向上 深度染色关联节点
        }else if(color[v] == c) return false; //已经染色 但是相邻颜色相同
    }
    return true;
}

bool isBigraph(){
    bool flag = true;
    for(int i = 1; i <= n; i ++ )
        if(!color[i])
            if(!dfs(i, 1)){
                flag = false;
                break;
            }
    return flag;
}

匈牙利算法 二分图的最大匹配

bool find(int u){
    for(int i = h[u]; i != -1; i = ne[i]){ //询问所有与u相关联的男生
        int v = e[i];
        if(!st[v]){        //男生还没被预定
            st[v] = true;
            if(match[v] == 0 || find(match[v])){
                //如果男生还没有女朋友 或者 男生更换原配换成现在的女孩
                match[v] = u;   //v的女朋友是u
                return true;
            }
        }
    }
    return false;
}

int max_match(){
    for(int i = 1; i <= n1; i ++ ){
        memset(st, 0, sizeof(st));
        if(find(i)) res ++ ;
    }
    return res;   
}

标签:图论,dist,int,基础,st,low,return,true,模板
From: https://www.cnblogs.com/MAKISE004/p/17318016.html

相关文章

  • 算法基础模板整理(高阶数据结构篇)
    树状数组动态区间和询问+点修改int lowbit(int x){    return x & -x;}void add(int x, int v){    for(int i = x; i <= n; i += lowbit(i)) tree[i] += v;}int query(int x){    int res = 0;    for(int i = x; i......
  • Java基础--数据结构
    数据结构Java工具包提供了强大的数据结构。在Java中的数据结构主要包括以下几种接口和类:枚举(Enumeration)、位集合(BitSet)、向量(Vector)、栈(Stack)、字典(Dictionary)、哈希表(Hashtable)、属性(Properties)以上这些类是传统遗留的,在Java2中引入了一种新的框架-集合框架(Collection)Java......
  • Java基础---数据类型
    数据类型Java的两大数据类型:内置数据类型、引用数据类型内置数据类型Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。byte、short、int、long、float、double、char、boolean基本类型范围byte:(8位)-128~127short:(26......
  • 优化 PMU 放置 (OPP) 问题的六种算法,包括两种模拟退火方法、两种图论过程和递归安全 N
    PMU优化配置 系统完全可观软件:MATLAB优化PMU放置(OPP)问题的六种算法,包括两种模拟退火方法、两种图论过程和递归安全N算法。 从MatPower获得的IEEE14,30,39,57和118bus系统数据,可得出系统完全可观所需配置pmu数量以及对应位置。配有对应文献ID:16150671665749743......
  • ts基础
    1//tsconfig.json项目中ts的配置文件2345//基本数据类型和any6varflag:boolean=true;78varnum:number=2;910varstr:string="abc";1112functionadd():void{13console.log("pp");14}1516ad......
  • 算法刷题-阶乘后的零(数学)、模拟计算器(算法初阶、基础知识)、解码方法(字符串、动态
    阶乘后的零(数学)给定一个整数n,返回n!结果中尾随零的数量。提示n!=n*(n-1)*(n-2)*...*3*2*1示例1:输入:n=3输出:0解释:3!=6,不含尾随0示例2:输入:n=5输出:1解释:5!=120,有一个尾随0示例3:输入:n=0输出:0提示:0<=n<=104**进阶:**你......
  • 【Linux】动静态库@基础IO —— 动静态库的制作使用
    制作动静态库1.动态库&静态库2.制作静态库2.1制作2.2使用3.制作动态库3.1制作3.2使用4.总结我们其实一直都在直接或间接的使用库,本文将介绍动静态库的制作和使用。从今天开始,你的朋友说,诶?你的作业借我看看。你就可以,哦不你也应该,勇敢的做个高尚的人,制作一个库扔给他~正文......
  • c++基础入门2
    一、数组1、概述所谓数组,就是一个集合,里面存放相同类型的数据元素特点:1、数组中的每个数据元素都是相同的数据类型2、数组是由连续的内存位置组成的2、一维数组(1)、定义方式:一维数组有中定义方式:1、数据类型数组名[数据长度];2、数据类型数组名[数据长度]={值1,值2.....};3、数据......
  • Java基础知识点内部类之成员内部类
    一:概述1.成员内部类顾名思义就是写在成员位置的,属于外部类成员。2.成员变量可以被一些修饰符所修饰,比如:private,default,public,static等。3.在成员内部类中,jdk16之前不能定义静态变量,jdk16开始才可以定义静态变量。二;获取内部类对象方法一;当成员内部类被private修饰时,在外部类中......
  • python爬虫基础
    下面是爬取网站源代码的代码,用的我们学校的教务处网站。。#!/usr/bin/envpythonimporturllibimporturllib2url='http://etc.sdut.edu.cn/eol/main.jsp'user_agent='Mozilla/5.0(X11;Ubuntu;Linuxx86_64;rv:42.0)Gecko/20100101Firefox/42.0'values={}values[......