图论笔记整理

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 条边)时,生成这棵树的总代价就是每条边的权重相加之和。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值