算法第四版- 4.1
无向图
1.单点连通性
class Solution {
public:
vector<unordered_set<int>> edge; //记录有向边,不能用并查集
unordered_set<int> visited; //是否访问过
bool dfs(int cur, int target) {
if(visited.count(cur)) return false;
visited.insert(cur);
if(cur == target) return true;
for(auto v : edge[cur]) {
if(dfs(v, target))
return true;
}
return false;
}
bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
edge.resize(n);
for(auto &e : graph)
edge[e[0]].insert(e[1]);
return dfs(start, target);
}
};
不过下面这种写法更加原生态的dfs,从结尾往前搜。
class Solution {
public:
bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
if(start == target) return true;
for(auto& e : graph)
if(e[1] == target)
return findWhetherExistsPath(n,graph,start,e[0]);
return false;
}
}
2.单点路径
LC剑指offer110,所有路径
很经典的dfs回溯。
class Solution {
public:
vector<vector<int>> ans;
vector<int> stk;
void dfs(vector<vector<int>>& graph, int x, int n) {
if (x == n) {
ans.push_back(stk);
return;
}
for (auto& y : graph[x]) {
stk.push_back(y);
dfs(graph, y, n);
stk.pop_back();
}
}
vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
stk.push_back(0);
dfs(graph, 0, graph.size() - 1);
return ans;
}
};
3.单点最短路径
最短路径大小
把上面这道题目看一看
然后输入输出为:
代码为:
#include <iostream>
#include <queue>
using namespace std;
static const int N = 100;
static const int INFTY = (1 << 21); //最大值
int n, M[N][N];
int d[N];
void bfs(int s) {
queue<int>q;
q.push(s);
for (int i = 0; i < n; i++) d[i] = INFTY;
d[s] = 0;
int u;
while (!q.empty()) {
u = q.front();
q.pop();
for (int v = 0; v < n; v++) {
if (M[u][v] == 0) continue;
if (d[v] != INFTY) continue;
d[v] = d[u] + 1;
q.push(v);
}
}
for (int i = 0; i < n; i++) {
cout << i + 1 << " " << ((d[i] == INFTY) ? (-1) : d[i]) << endl;
}
}
int main()
{
cout << "输入\n";
int u, k, v;
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
M[i][j] = 0;
}
for (int i = 0; i < n; i++) {
cin >> u >> k;
u--;
for (int j = 0; j < k; j++) {
cin >> v;
v--;
M[u][v] = 1;
}
}
cout << "输出:\n";
bfs(0);
return 0;
}
代码是《挑战程序设计竞赛2》上P236.
关于最短路径,还有Dijkstra,Floyd,Spfa,Ford
BFS只能适用于无权图,即权值为1
重翻白书,感觉受益良多,半年前看的了。不知道等大三校招的时候能不能把这本书全学会。感觉大四毕业也可能不会。
4.连通性/连通分量
连通分量其实就是岛屿数量
还是比较推荐用并查集。
并查集求岛屿数量
5.检测环
这个课本上的代码是错的。。。
首先可以肯定这是有向图的东西。(因为我在测试中改变边的方向,输出答案变化了。所以肯定不是无向图)
但是针对一些特殊的图,又跑不出正确结果。我可以勘误了。。。
6.双色问题(图的二分性)
LC785判断二分图
染色,记忆化递归
class Solution {
public:
bool dfs(const vector<vector<int>> &g, int i, int c, vector<int> &v) { //返回第i个点染c色能否成功
if (v[i] != -1) return v[i] == c; //第i个点已染过
v[i] = c; //对第i个点染上c色
for (int j : g[i]) if (!dfs(g, j, !c, v)) return false; //递归相邻的点,c => !c 换色
return true;
}
bool isBipartite(vector<vector<int>>& graph) {
const int n = graph.size();
vector<int> v(n, -1); //-1表示待染色
for (int i = 0; i < n; i++) if (v[i] == -1 && !dfs(graph, i, 0, v)) return false;
return true;
}
};