基环树(pseudotree)入门

news2024/12/24 9:07:32

目录

  • 无向基环树
    • 找环,[题目](https://www.luogu.com.cn/problem/P8655)
      • 拓扑排序找环
      • 并查集找环
      • dfs找环
    • 内向基环树
      • [2876. 有向图访问计数](https://leetcode.cn/problems/count-visited-nodes-in-a-directed-graph/description/)
      • [2127. 参加会议的最多员工数](https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/description/)

无向基环树

找环,题目

给定一个图,N个点N条边,只有一个环,输出换上的点。

拓扑排序找环

#include <bits/stdc++.h>
using namespace std;

// 点的编号从1开始
const int N = 100010;
int n;
vector<int> g[N];
vector<int> in, visit;

void topologicalOrder() {
	queue<int> q;
	//把入度为1的点入队
	for (int i = 1; i <= n; i++) {
		if (in[i] == 1) q.push(i), visit[i] = 1;
	}
	while (q.size()) {
		int u = q.front();
		q.pop();
		for (int v: g[u]) {
			in[v]--;
			if (in[v] == 1) q.push(v), visit[v] = 1;
		}
	}
}

void print() {
	for (int i = 1; i <= n; i++) 
		if (!visit[i]) cout << i << " ";
}

int main()
{
	cin >> n;
	in = vector<int>(n);
	visit = vector<int>(n);
	for (int i = 1; i <= n; i++) {
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
		in[u]++;
		in[v]++;
	}
	topologicalOrder();
	print();
	return 0;
}

并查集找环

#include <bits/stdc++.h>
using namespace std;

// 并查集模板
struct DSU {
    std::vector<int> f, siz;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};

// 点的编号从1开始
const int N = 100010;
int n;
vector<int> g[N];
vector<int> path;

void findRing(int pre, int u, int v, int index) {
	path[index] = u;
	if (u == v) {
		sort(path.begin(), path.begin() + index + 1);
		for (int i = 0; i <= index; i++) cout << path[i] << " ";
		return ;
	}
	
	for (int j: g[u]) {
		if (j == pre) continue;
		findRing(u, j, v, index + 1);
	}
}

int main()
{
	cin >> n;
	DSU dsu(n);
	path = vector<int>(n);
	for (int i = 1; i <= n; i++) {
		int u, v;
		cin >> u >> v;
		if (dsu.find(u) != dsu.find(v)) {
			// 两个点不联通
			g[u].push_back(v);
			g[v].push_back(u);
			dsu.merge(u, v);
		} else {
			// u和v已经联通了,那么我们在图中寻找从u到v的路径,这些都是环上的点
			findRing(-1, u, v, 0);
		}
	}
	return 0;
}

dfs找环

#include <bits/stdc++.h>
using namespace std;


// 点的编号从1开始
const int N = 100010;
int n, idx;
vector<int> g[N];
vector<int> path, dfn, fa;

void dfs(int u){
	if (dfn[u] != 0) return ;
    dfn[u]=++idx;
    for(int v: g[u]){
        if(v==fa[u]) continue;
        if(!dfn[v]) fa[v]=u,dfs(v);
        else {
			if(dfn[v]<dfn[u]) continue;
			path.push_back(v);
			for(; v != u; v=fa[v]) path.push_back(fa[v]);
		}
    } 
    return;
}


int main()
{
	cin >> n;
	idx = 0;
	dfn = vector<int>(n + 1);
	fa = vector<int>(n + 1);
	for (int i = 1; i <= n; i++) {
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for (int i = 1; i <= n; i++) dfs(i);
	sort(path.begin(), path.end());
	for (int v: path) cout << v << " ";
	return 0;
}

内向基环树

每个点有且只有一个出边
内向基环树

2876. 有向图访问计数

class Solution {
public:
    vector<int> countVisitedNodes(vector<int>& g) {
        int n = g.size(); //节点的个数,节点的编号从0开始
        vector<vector<int>> rg(n); //反图
        vector<int> in(n);
        for (int x = 0; x < n; x++) {
            int y = g[x];
            // 一条从x到y的边: x -> y
            in[y]++;
            rg[y].push_back(x); //添加反向边到反图中
        }
        
        // 拓扑排序,剪掉g上所有的树枝
        queue<int> q;
        for (int i = 0; i < n; i++) if (in[i] == 0) q.push(i);
        while (q.size()) {
            int x = q.front();
            q.pop();
            int y = g[x];
            if (--in[y] == 0) q.push(y);
        }
        
        //答案数组, 表示的是从i点出发能访问到的节点数
        vector<int> ans(n, 0);
        
        function<void(int, int)> rdfs = [&](int x, int depth) {
            ans[x] = depth;
            // 以环上的点为根,通过反向边去搜树枝点
            // in[y]==0: 树枝点
            for (int y: rg[x]) if (in[y] == 0) rdfs(y, depth + 1);
        };
        
        for (int i = 0; i < n; i++) {
            // 0: 树枝点 -1: 基环上的点
            if (in[i] <= 0) continue;
            
            vector<int> ring;
            for (int x = i; ; x = g[x]) {
                in[x] = -1; // 基环上的点标记为-1,避免重复访问
                ring.push_back(x);
                if (g[x] == i) break; // 回到起点i了
            }
            for (int x: ring) rdfs(x, ring.size());
        }
        return ans;
    }
};

2127. 参加会议的最多员工数


class Solution {
public:
    int maximumInvitations(vector<int>& favorite) {
        int n = favorite.size();
        vector<int> in(n);
        // x -> y
        for (int y: favorite) in[y]++;
        vector<vector<int>> rg(n); // 反图
        
        queue<int> q;
        for (int i = 0; i < n; i++) if (in[i] == 0) q.push(i);
        while (q.size()) {
            int x = q.front();
            q.pop();
            int y = favorite[x];
            rg[y].push_back(x);
            if (--in[y] == 0) q.push(y);
        }
        
        // 在反图上搜索树枝上最深的链
        function<int(int)> rdfs = [&](int x) -> int {
            int max_depth = 1;
            for (int son: rg[x]) max_depth = max(max_depth, rdfs(son) + 1);
            return max_depth;
        };
        
        int max_ring_size = 0, sum_chain_size = 0;
        for (int i = 0; i < n; i++) {
            if (in[i] == 0) continue;
            
            // 搜索基环上的点
            in[i] = 0; //标记,避免重复访问
            int ring_size = 1;
            for (int x = favorite[i]; x != i; x = favorite[x]) {
                in[x] = 0;
                ring_size++;
            }
            
            if (ring_size == 2) sum_chain_size += rdfs(i) + rdfs(favorite[i]);
            else max_ring_size = max(max_ring_size, ring_size);
        }
        return max(max_ring_size, sum_chain_size);
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1227316.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

公司内部网络架设悟空CRM客户管理系统 cpolar无需公网IP实现内网,映射端口外网访问

1、什么是内网穿透&#xff1f; 内网穿透&#xff0c;即内网映射&#xff0c;内网IP端口映射到外网的过程。是一种主动的操作&#xff0c;需要本人一些内网的权限。比如在公司自己电脑&#xff0c;将办公OA发布到互联网&#xff0c;然后提供外网在家或出差在外连接访问。 可以…

动态改标题

<el-dialog :title"showTitle" :visible"showDialog" close"close"> </el-dialog>使用计算属性 computed: {showTitle() {//这里根据点击的是否有具体点击的那个id来判断return this.form.id ? "编辑部门" : "新增部…

Linux:安装软件的两种方式rpm和yum

一、rpm方式 1、简单介绍 RPM是RedHat Package Manager的缩写&#xff0c;它是Linux上打包和安装的工具。通过rpm打包的文件扩展名是.RPM。这个安装包就类似Windows系统中的.exe文件。rpm工具实现Linux上软件的离线安装。 2、软件相关信息的查询命令 查询Linux系统上所有已…

docker的基本使用以及使用Docker 运行D435i

1.一些基本的指令 1.1 容器 要查看正在运行的容器&#xff1a; sudo docker ps 查看所有的容器&#xff08;包括停止状态的容器&#xff09; sudo docker ps -a 重新命名容器 sudo docker rename <old_name> <new_name> <old_name> 替换为你的容器名称…

模块化Common JS 和 ES Module

目录 历程 1.几个函数&#xff1a;全局变量的污染&#xff0c;模块间没有联系 2.对象&#xff1a;暴露成员&#xff0c;外部可修改 3.立即执行函数&#xff1a;闭包实现模块私有作用域 common JS module和Module 过程 模块依赖&#xff1a;深度优先遍历、父 -> 子 -…

辅助笔记-Jupyter Notebook的安装和使用

辅助笔记-Jupyter Notebook的安装和使用 文章目录 辅助笔记-Jupyter Notebook的安装和使用1. 安装Anaconda2. conda更换清华源3. Jupter Notebooks 使用技巧 笔记主要参考B站视频“最易上手的Python环境配置——Jupyter Notebook使用精讲”。 Jupyter Notebook (此前被称为IPyt…

C++初阶 日期类的实现(上)

目录 一、前置准备 1.1获得每月的天数 1.2获得每年的天数 1.3构造函数&#xff0c;析构函数和拷贝构造函数 二、日期与天数的,-,,-实现 2.1运算符重载 2.2运算符的实现 2.3-运算符的实现 2.4-运算符的实现 三、&#xff0c;--的实现 3.1前置&#xff0c;后置的实现 …

《洛谷深入浅出基础篇》P5266 学籍管理——map的应用

上链接&#xff1a;P5266 【深基17.例6】学籍管理 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P5266#submit 题干&#xff1a; 题目描述 您要设计一个学籍管理系统&#xff0c;最开始学籍数据是空的&#xff0c;然后该系统能够支持下面的…

Vue3--Vue Router详解--学习笔记

1. 认识vue-router Angular的ngRouter React的ReactRouter Vue的vue-router Vue Router 是Vue.js的官方路由&#xff1a; 它与Vue.js核心深度集成&#xff0c;让Vue.js构建单页应用&#xff08;SPA&#xff09;变得非常容易&#xff1b;目前Vue路由最新的版本是4.x版本。 v…

德迅云安全告诉您 网站被攻击怎么办-SCDN来帮您

随着互联网的发展给我们带来极大的便利&#xff0c;但是同时也带来一定的安全威胁&#xff0c;网络恶意攻击逐渐增多&#xff0c;很多网站饱受困扰&#xff0c;而其中最为常见的恶意攻击就是cc以及ddos攻击。针对网站攻击&#xff0c;今天为您介绍其中一种防护方式-SCDN&#x…

计算机毕业设计选题推荐-点餐微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

吴恩达《机器学习》9-1-9-3:反向传播算法、反向传播算法的直观理解

一、正向传播的基础 在正向传播中&#xff0c;从神经网络的输入层开始&#xff0c;通过一层一层的计算&#xff0c;最终得到输出层的预测结果。这是一种前向的计算过程&#xff0c;即从输入到输出的传播。 二、反向传播算法概述 反向传播算法是为了计算代价函数相对于模型参数…

贝锐蒲公英路由器X4C如何远程访问NAS?

在目前网盘前路坎坷的情况下&#xff0c;私人云盘已然是一种新的趋势&#xff01;那自己打造一个私有云盘&#xff0c;是否需要高成本或是高门槛呢&#xff1f;其实并不用&#xff01;蒲公英针对个人玩家打造了全方位的私有云解决方案。 &#xff08;1&#xff09;入门级玩家只…

argocd

部署argocd https://github.com/argoproj/argo-cd/releases kubectl create namespace argocd kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.9.1/manifests/install.yaml官网 https://argo-cd.readthedocs.io/en/stable/ kubectl crea…

基于灰色神经网络的预测算法——订单需求预测

大家好&#xff0c;我是带我去滑雪&#xff01; 灰色系统理论的不确定性处理与神经网络的非线性建模相结合&#xff0c;有望更好地处理实际问题中的不确定性和复杂性。本期使用灰色神经网络实现预测冰箱订单需求。 一、问题背景与模型建立 &#xff08;1&#xff09;灰色理论…

物联网AI MicroPython学习之语法 TIMER硬件定时器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; TIMER 介绍 模块功能: 硬件定时器模块 接口说明 Timer - 构建Timer对象 函数原型&#xff1a;Timer(id)参数说明&#xff1a; 参数类型必选参数&#xff1f;说明idintY硬件定时器外设模块id&#xff1a…

计算机毕业设计项目选题推荐(免费领源码)java+Springboot+mysql高校自习室座位预约管理系统67512

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对高校自习室座位预约管理系统等问题&#xf…

IIC 实验

IIC 简介 IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线&#xff0c;用于连接微 控制器以及其外围设备。它是由数据线 SDA 和时钟线 SCL 构成的串行总线&#xff0c;可发送和接收数 据&#xff0c;在 CPU 与被控 IC 之间、IC 与 IC 之间进行双…

VBA之Word应用:文档(Document)的书签

《VBA之Word应用》&#xff08;版权10178982&#xff09;&#xff0c;是我推出第八套教程&#xff0c;教程是专门讲解VBA在Word中的应用&#xff0c;围绕“面向对象编程”讲解&#xff0c;首先让大家认识Word中VBA的对象&#xff0c;以及对象的属性、方法&#xff0c;然后通过实…

虚拟机配置完NAT模式之后可以和主机ping通但是ping 百度显示:网络不可达

具体linux网络配置看这&#xff1a;http://t.csdnimg.cn/KRami 解决方案如下&#xff1a; 如果这里网关为空&#xff0c;那么和我遇到的问题一样网关没有设置上&#xff0c;在这直接配置网关之后重启即可