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的下标直接表示节点。
如:
0:1,2
1:2
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占用空间比较大,其次就是文章来源:https://www.toymoban.com/news/detail-535522.html
5 最小生成树
一个图中可能存在多条相连的边,我们一定可以从一个图中挑出一些边生成一棵树。这仅仅是生成一棵树,还未满足最小,当图中每条边都存在权重时,这时候我们从图中生成一棵树(n - 1 条边)时,生成这棵树的总代价就是每条边的权重相加之和。文章来源地址https://www.toymoban.com/news/detail-535522.html
到了这里,关于图论笔记整理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!