851. 喧闹和富有 - 力扣(LeetCode)
复习一下链式前向星
注意题目要求的是拓扑序严格大于的数,这个时候按顺序统计的拓扑序并不是严格大于的关系,因此要在拓扑图中不断更新
class Solution {
const static int N = 510 * 510;
public:
int ne[N], idx, h[N], e[N], ind[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
vector<int> loudAndRich(vector<vector<int>>& richer, vector<int>& quiet) {
//更有钱且最安静的人
//寻找拓扑序,然后找到更安静的人
//b ---> a
idx = 0;
memset(h, -1, sizeof h);
int n = quiet.size();
for(int i = 0; i < richer.size(); i ++ )
{
int a = richer[i][0], b = richer[i][1];
add(a, b);//a到b的一条边
ind[b] ++;
}
vector<int> ans(n);
queue<int> q;
for(int i = 0; i < n; i ++ )
{
if(!ind[i]) q.push(i);
ans[i] = i;//初始答案
}
while(q.size())
{
int u = q.front();
q.pop();
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];//u比j更有钱
ind[j] --;
if(quiet[ans[j]] > quiet[ans[u]])//u更加安静
ans[j] = ans[u];
if(!ind[j]) q.push(j);
}
}
return ans;
}
};
搜索版本,对每个点搜索拓扑序比他大的点,更新最小quiet
class Solution {
public:
vector<int> loudAndRich(vector<vector<int>> &richer, vector<int> &quiet) {
int n = quiet.size();
vector<vector<int>> g(n);
for (auto &r : richer) {
g[r[1]].emplace_back(r[0]);
}
vector<int> ans(n, -1);
function<void(int)> dfs = [&](int x) {
if (ans[x] != -1) {
return;
}
ans[x] = x;
for (int y : g[x]) {
dfs(y);
if (quiet[ans[y]] < quiet[ans[x]]) {
ans[x] = ans[y];
}
}
};
for (int i = 0; i < n; ++i) {
dfs(i);
}
return ans;
}
};
310. 最小高度树 - 力扣(LeetCode)
对于无向图,如何进行拓扑排序,可以设置入度最小为1,这时拓扑序是外层小于内层。
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
//最大值最小
//删除叶子节点,最终会剩下一个点或者两个点,如果有第三个点,那么可以删除
vector<int> g[n];
vector<int> ind(n);
for(int i = 0; i < n - 1; i ++ )
{
g[edges[i][0]].push_back(edges[i][1]);
g[edges[i][1]].push_back(edges[i][0]);
ind[edges[i][0]] ++;
ind[edges[i][1]] ++;
}
queue<int> q;
vector<bool> st(n);
vector<int> dist(n);
int cnt = 0;
for(int i = 0; i < n; i ++ )
{
if(ind[i] == 1)
{
q.push(i);
dist[i] = 0;
}
}
while(n - (cnt ++) > 2)//最终会剩余两个或者一个,这时到达了最内层
{
int u = q.front();
q.pop();
st[u] = true; // 删除
for(int i = 0; i < g[u].size(); i ++ )
{
int j = g[u][i];
if(!st[j])//为了防止反复,经过的不会再经过
{
dist[j] = max(dist[j], dist[u] + 1);
if(-- ind[j] == 1) q.push(j);
}
}
}
int res = *max_element(dist.begin(), dist.end());
vector<int> ans;
for(int i = 0; i < n; i ++ )
if(dist[i] == res) ans.push_back(i);
return ans;
}
};
802. 找到最终的安全状态 - 力扣(LeetCode)
反向建图 + 拓扑排序
一个节点不会进入环则是安全的,正向无法保证这个点的入度为0,反向建图,从终点开始拓扑排序,找到所有满足要求的点
class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
//找到拓扑图的所有点
int n = graph.size();
vector<int> ind(n);
vector<int> g[n];
for(int i = 0; i < n; i ++ )
{
for(int j = 0; j < graph[i].size(); j ++ )
{
ind[i] ++;
g[graph[i][j]].push_back(i);//反向边
}
}
vector<int> ans;
queue<int> q;
for(int i = 0; i < n; i ++ )
{
if(!ind[i])
{
q.push(i);
}
}
while(q.size())
{
auto u = q.front();
q.pop();
ans.push_back(u);
for(int i = 0; i < g[u].size(); i ++ )
{
int j = g[u][i];
ind[j] --;
if(!ind[j]) q.push(j);
}
}

本文通过多个力扣(LeetCode)题目,深入探讨了图论在解决实际问题中的应用,包括拓扑排序、最短路径、并查集、深度优先搜索等算法。涉及题目包括最小高度树、找到最终的安全状态、接雨水II、最小体力消耗路径、水位上升的泳池中游泳、网络延迟时间和K站中转内最便宜的航班等,展示了图论在解决复杂问题中的强大能力。
最低0.47元/天 解锁文章
2065

被折叠的 条评论
为什么被折叠?



