图论笔记整理

这篇具有很好参考价值的文章主要介绍了图论笔记整理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1466
#include <string>
#include<vector>
#include<unordered_set>
#include<stack>
#include<iostream>
using namespace std;


class Solution {
public:
    vector<int> path;
    vector<vector<int>> res;
    unordered_set<int> set;
    int minReorder(int n, vector<vector<int>>& connections)
    {
        int result = 0;
        vector<vector<int>> G(n);//无向图
        unordered_set<string> set_str;
        for (int i = 0; i < connections.size(); i++)
        {
            int a = connections[i][0];
            int b = connections[i][1];
            G[a].push_back(b);
            G[b].push_back(a);
            set_str.insert(to_string(a) + "#" + to_string(b));

        }

        backing(0, G);

        for (int i = 0; i < res.size(); i++)
        {
            for (int j = 0; j < res[i].size() - 1; j++)
            {
                int a = res[i][j];
                int b = res[i][j + 1];

                if (set_str.find(to_string(a) + "#" + to_string(b)) != set_str.end())
                {
                    set_str.erase(to_string(a) + "#" + to_string(b));
                    result++;
                }
            }
                    
        }
        return result;


    }

    void backing(int a, vector<vector<int>>& G)
    {
        path.push_back(a);
        set.insert(a);

        int mark = 0;
        for (int i = 0; i < G[a].size(); i++)
        {
            if (set.find(G[a][i]) == set.end())//在set中没找到,所以还是有没遍历完的
            {
                mark = 1;
                break;
            }
        }

        if (mark == 0)//都遍历完了
        {
            res.push_back(path);
            return;
        }

        for (int i = 0; i < G[a].size(); i++)
        {
            if (set.find(G[a][i]) != set.end())
            {
                continue;
            }

            backing(G[a][i], G);

            path.pop_back();
            set.erase(G[a][i]);
        }
    }
};


class Solution1 {
public:
    unordered_set<int> set;
    unordered_set<string> set_str;
    int minReorder(int n, vector<vector<int>>& connections)
    {

        int result = 0;
        vector<vector<int>> G(n);//无向图
        stack<int> stk;
        int res = 0;
        for (int i = 0; i < connections.size(); i++)
        {
            int a = connections[i][0];
            int b = connections[i][1];
            G[a].push_back(b);
            G[b].push_back(a);
            set_str.insert(to_string(a) + "#" + to_string(b));

        }
        stk.push(0);
        set.insert(0);

        while (!stk.empty())
        {
            int a = stk.top();
            stk.pop();

            for (int i = 0; i < G[a].size(); i++)
            {
                if (set.find(G[a][i]) == set.end())
                {
                    if (set_str.find(to_string(a) + "#" + to_string(G[a][i])) != set_str.end())
                    {
                        res++;
                    }
                    stk.push(G[a][i]);
                    set.insert(G[a][i]);
                }
            }

        }
        return res;



    }
};

int main()
{
    int n = 5;
    vector<vector<int>> nums = { {1,0},{1,2},{3,2},{3,4} };
    Solution slu;
    cout << slu.minReorder(n, nums);
    return 0;

}

#include<string>
#include<vector>
#include<queue>
#include<unordered_set>
#include<unordered_map>
using namespace std;

class Node {
public:
    int val;
    vector<Node*> neighbors;
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};

#include<string>
#include<vector>
#include<queue>
using namespace std;

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) 
    {
        int n=numCourses;
        vector<vector<int>> g(n);//g[i]记录的是第i个节点指向的节点的编号
        vector<int> outedge(n,0);//每个节点的入度
        vector<int> res;
        for(auto it:prerequisites)
        {
            g[it[1]].push_back(it[0]);
            outedge[it[0]]++;
        }
        queue<int> que;
        for(int i=0;i<outedge.size();i++)
        {
            if(outedge[i]==0)
                que.push(i);
        }

        while(!que.empty())
        {
            int node=que.front();
            que.pop();
            res.push_back(node);
            for(int i=0;i<g[node].size();i++)
            {
                outedge[g[node][i]]--;
                if(outedge[g[node][i]]==0)
                    que.push(g[node][i]);
            }
        }
        return res.size()==n;
    }
};
#include<string>
#include<vector>
#include<queue>
using namespace std;

//图的拓扑排序-----图的邻接表表示法:vector<vector> vec中的vec[i]代表的是节点i指向的元素的位置
//更一般的是:vector<vector>

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) 
    {
        int n=numCourses;
        vector<vector<int>> g(n);//邻接表存储有向图
        vector<int> outedge(n,0);//每个节点的入度
        vector<int> res;
        for(int i=0;i<prerequisites.size();i++)
        {
            vector<int> temp=prerequisites[i];
            g[temp[1]].push_back(temp[0]);

            //入度
            outedge[temp[0]]++;
        }

        queue<int> que;

        for(int i=0;i<n;i++)
        {
            if(outedge[i]==0)
            {
                que.push(i);
            }
        }

        while(!que.empty())
        {
            int node=que.front();
            que.pop();
            res.push_back(node);

            for(int i=0;i<g[node].size();i++)
            {
                outedge[g[node][i]]--;
                if(outedge[g[node][i]]==0)
                {
                    que.push(g[node][i]);
                }
            }
        }
        if(res.size()!=n)
            return{};
        return res;




    }
};
# 1  图的统一表示方法:邻接表法

### 1)如果节点本身就是0~n-1标号的--(笔试面试大部分都是这种)

那么直接使用一个vector< vector<> >就可以表示图。vector的下标直接表示节点。
如:
01,2
12
2:0,1

这个图就能使用vector< vector< int> >={{1,2},{2},{0,1}}.

### 2)节点本身并不是通过0~n-1 来表示的
首先要知道的是,有很多种的定义方式这里采取的是,网上最多的是,自定义顶点类型和自定义边节点类型,但是那样太复杂了,以后统一使用下面的简单的通用表示法!

核心:
- 节点全部都是Node类型(自定义);
- 使用一个哈希表来记录节点值和Node*的对应关系

~~~cpp
#include<string>
#include<vector>
#include<list>
#include<iostream>
#include<queue>
#include<unordered_set>
#include<unordered_map>
using  namespace std;

//图的邻接表表示:就是一个数组加上N条链表

// 边结点
struct Node
{
    int val;
    vector<Node*> vecs;
    Node(int val_):val(val_)
    {
        
    }
};

unordered_map<int ,Node*> map;//记录的是节点值和节点地址的对用关系

vector<Node*> create()
{
    
    cout<<"输入图的点树和边数:";
    int nodenum;
    int arcnum;
    cin>>nodenum>>arcnum;
    vector<Node*> g(nodenum,nullptr);

    cout<<"输入图的点的值,以空格作为分割:";
    for(int i=0;i<nodenum;i++)
    {
        Node* node=new Node(0);
        cin>>node->val;
        map[node->val]=node;
        g[i]=node;
    }

    cout<<"输入边连接的两个点:";
    for(int i=0;i<arcnum;i++)
    {
        int start ;
        int end;
        cin>>start;
        cin>>end;

        Node * startnode=map[start];
        Node *endnode=map[end];
        startnode->vecs.push_back(endnode);
        endnode->vecs.push_back(startnode);
   
    }

    return g;

}

void print()
{
    vector<Node * > g=create();
    for(int i=0;i<g.size();i++)
    {
        cout<<g[i]->val<<" ";
        for(auto it:g[i]->vecs)
        {
            cout<<it->val<<" ";
        }
        cout<<endl;
    }
    return ;
}


int main()
{
  
    print();
    return 0;

}

2 图的DFS和BFS

1) 图的宽度优先遍历

//从图的node出发进行广度优先遍历
/*
    使用队列实现
    从源节点开始依次按照宽度进队列,然后弹出
    每弹出一个点,做业务逻辑处理,然后把该节点所有没有进过队列中的邻接点放入队列
    直到队列为空
*/
vector<int> BFS(Node * node)
{

    vector<int> res;
    if(node==nullptr)
        return res ;
    queue<Node* > que;
    unordered_set<Node*> set;//记录已经遍历过的节点

    que.push(node);
    set.insert(node);

    
    
    while(!que.empty())
    {
        Node * temp=que.front();
        que.pop();
        //弹出节点的时候进行业务逻辑处理
        res.push_back(temp->val);
        for(auto it:temp->vecs)
        {
            if(set.find(it)==set.end())
            {
                set.insert(it);
                que.push(it);

            }
        }
    }
    return res;
}

2)深度优先遍历


/*深度优先搜素
    利用栈实现
    从源节点开始把节点按照深度入栈,然后弹出
    每弹出一个点,把该节点下一个没有进过栈的邻接点放入栈
    直到栈变空
*/
vector<int> DFS(Node * node)
{
    vector<int> res;
    if(node==nullptr)
        return res;
    unordered_set<Node* > set;
    stack<Node* > stk;
    stk.push(node);
    set.insert(node);

    while (!stk.empty())
    {
        /* code */
        Node * temp=stk.top();
        stk.pop();
        res.push_back(temp->val);
        for(auto it:temp->vecs)
        {
            if(set.find(it)==set.end())
            {
                set.insert(it);
                stk.push(it);
            }
        }
        
    }
    return res;
}

3 拓扑排序

见课程表

4 DFS和BFS的区别是什么

1、使用的数据结构不同

2、运行逻辑不同
bfs:
从源节点开始依次按照宽度进队列,然后弹出
每弹出一个点,做业务逻辑处理,然后把该节点所有没有进过队列中的邻接点放入队列
直到队列为空

dfs
从源节点开始把节点按照深度入栈,然后弹出
每弹出一个点,把该节点下一个没有进过栈的邻接点放入栈
直到栈变空

3、应用场景不同

  • 如果知识要找到某个结果是否存在,那么DFS会更高效。因为DFS会首先的吧一种可能搜索到底,才会回溯去搜索下一种情况,只要找到一种情况满足则可以返回了。但是BFS必须所有可能的情况同时尝试,再找到一种满足条件的结果的同时,也尝试了很多不必要的路径。

  • 如果是要找到所有可能结果中最短或者最优的,那么BFS会更加高效,因为BFS是一种一种的尝试,在把所有可能情况尝试完之前,无法确定那个是最短的,所以DFS必须把所有情况都找一遍,才能确定最终答案(DFS的优化就是剪枝,不剪枝很容易超时)。而BFS从一开始就是尝试所有情况,所以只要找到第一个到达的那个点,那就是最优解。所以可以直接返回了,其他情况可以省略了,所以在这种情况下,BFS更高效。

4、至于使用空间的大小
如果要是以复杂度来论的话,复杂度是相同的,最坏的空间复杂度都是N
实际上呢,和图的形状有关系,当图的深度比较大,DFS占用空间比较大,其次就是

5 最小生成树

一个图中可能存在多条相连的边,我们一定可以从一个图中挑出一些边生成一棵树。这仅仅是生成一棵树,还未满足最小,当图中每条边都存在权重时,这时候我们从图中生成一棵树(n - 1 条边)时,生成这棵树的总代价就是每条边的权重相加之和。文章来源地址https://www.toymoban.com/news/detail-535522.html

到了这里,关于图论笔记整理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 图论——最短路 学习笔记

    其实是复习性质的,主要是总结,证明什么的,等上大学再说。 单源最短路:从一个点 (q) 出发,到其他所有点的最短路。 全源最短路:任意两点见最短路。 算法 Floyd Johnson Bellman–Ford SPFA Dijkstra 类型 全源 全源 单源 单源 单源 作用于 任意图 任意图 任意图 任意图 非负权

    2024年02月05日
    浏览(46)
  • C++学习笔记——图论

    图是由 节点(v)和边(e) 组成的,把图记作二元组G=(v,e) 无向图                                                                    有向图 边是双向的,v1可以到v2,v2也能到v1                 边是单向的,v1可以到v2,但v2不能到v1 无权图               

    2024年04月12日
    浏览(29)
  • 图论——Kruskal 重构树 学习笔记

    最大生成树将部分内容倒置即可 基本信息 求解最小生成树 时间复杂度: (O(m log m)) 更适合稀疏图 算法思想 按照边权从小到大排序 依次枚举每一条边,如果这一条边两侧不连通,则加入这条边 代码 点击查看代码 算法思想 在构建最小生成树的时候,设现在枚举到了一条要

    2024年02月08日
    浏览(37)
  • 图论——Kruskal重构树 学习笔记

    最大生成树将部分内容倒置即可 基本信息 求解最小生成树 时间复杂度: (O(m log m)) 更适合稀疏图 算法思想 按照边权从小到大排序 依次枚举每一条边,如果这一条边两侧不连通,则加入这条边 代码 点击查看代码 算法思想 在构建最小生成树的时候,设现在枚举到了一条要

    2024年02月08日
    浏览(37)
  • Tarjan 算法——图论学习笔记

    在图论问题中,我们经常去研究一些连通性问题,比如: 有向图的联通性:传递闭包——Floyd 算法; 有向图连通性的对称性:强联通分量(SCC)——Tarjan 算法缩点; 无向图的联通性:并查集; 无向图的关键边:桥(割边)、边双——Tarjan 算法缩点; 无向图的关键点:割点

    2024年02月02日
    浏览(36)
  • 图论做题笔记:bfs

    题目: 基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是  \\\'A\\\' 、 \\\'C\\\' 、 \\\'G\\\'  和  \\\'T\\\'  之一。 假设我们需要调查从基因序列  start  变为  end  所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如, \\\"AACCGGTT\\\" -- \\\"AACCGGTA

    2024年04月09日
    浏览(42)
  • MCM备赛笔记——图论模型

    Key Concept 图论是数学的一个分支,专注于研究图的性质和图之间的关系。在图论中,图是由顶点(或节点)以及连接这些顶点的边(或弧)组成的。图论的模型广泛应用于计算机科学、通信网络、社会网络、生物信息学、城市交通规划等多个领域。 无向图 : 顶点之间的边没

    2024年01月21日
    浏览(39)
  • 离散数学之图论复习笔记

    图的定义 一个图 G 是一个序偶〈 V ( G ), E ( G )〉,记为 G =〈 V ( G ), E ( G )〉。其中 V ( G )是非空结点集合, E ( G )是边集合,对 E ( G )中的每条边,有 V ( G )中的结点的有序偶或无序偶与之对应。 图G的结点与边之间的关系 邻接点 :同一条边的两个端点。 孤立点 :没有边与之关

    2024年02月08日
    浏览(36)
  • 刷题笔记26——图论二分图判定

    世界上的事情,最忌讳的就是个十全十美,你看那天上的月亮,一旦圆满了,马上就要亏厌;树上的果子,一旦熟透了,马上就要坠落。凡事总要稍留欠缺,才能持恒。 ——莫言 visited数组是在如果有环的情况下,防止在图中一直绕圈设置的,类似于剪枝操作,走过了就没必要再走一遍

    2024年02月07日
    浏览(38)
  • 刷题笔记25——图论课程表

    为了最终理解你所不理解的,你必须经历一条愚昧无知的道路。为了占有你从未占有的东西,你必须经历被剥夺的道路。为了达到你现在所不在的名位,你必须经历那条你不在其中的道路。——艾略特 非常奇妙,我最初的错误是如下,在找到目标节点后直接加入到res中,但是

    2024年02月07日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包