SCC缩点

一、P2812 校园网络【[USACO]Network of Schools加强版】

P2812 校园网络【[USACO]Network of Schools加强版】

1、算法简析

首先,建立一张有向图——学校是节点,学校间的单向线路是有向边。 Q 1 Q_1 Q1:选出若干个节点,从这些节点出发可以到达其它的任意节点(即不考虑选出的节点),求这些节点数量的最小值。 Q 2 Q_2 Q2:添加若干条有向边,使有向图中任意两点可以相互到达,求这些边数量的最小值。

我们知道,在强连通分量中,任意两点可以相互到达,所以对于一个强连通分量,只要有一个节点作为代表即可。因此,我们可以通过 T a r j a n Tarjan Tarjan 算法求 S C C SCC SCC,用 S C C SCC SCC 的编号建立新的节点,代替相应的强连通分量。然后建立新图,对原图进行了简化。这就是 S C C SCC SCC 缩点问题。

接下来,在缩点后的新图(无环图 D A G DAG DAG)上讨论问题。

对于 Q 1 Q_1 Q1,若一个节点的入度为 0 0 0,则其它节点不可能到达它,所以该点必须作为起点。因此,入度为 0 0 0 的节点个数即所求。

对于 Q 2 Q_2 Q2,要使任意两点可以相互到达,那么任意节点的出入度都不能为 0 0 0。又要使添加的边数最少,可以令出度为 0 0 0 的节点指向入度为 0 0 0 的节点。若两种节点的数量相等,则该数即所求。若数量不等,则取二者的最大值。因此出入度为 0 0 0 的节点数的最大值即所求。

2、Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int MAX = 1e4 + 3;
int N;
vector<int> G[MAX];
int dfn[MAX], low[MAX], tot;
stack<int> S;
bool instk[MAX];
int scc[MAX], cnt; 
int din[MAX], dout[MAX];      // din[x] -- 缩点i的入度; dout[x] -- 缩点i的出度

void tarjan(int u)
{
	dfn[u] = low[u] = ++tot;
	S.push(u), instk[u] = true;
	
	for (int i = 0; i < G[u].size(); ++i)
	{
		int v = G[u][i];
		if (!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (instk[v])
			low[u] = min(low[u], dfn[v]);
	}
	
	if (dfn[u] == low[u])
	{
		int t;
		++cnt;
		do
		{
			t = S.top();
			S.pop(), instk[t] = false;
			scc[t] = cnt;
		} while (t != u);
	}
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	cin >> N;
	for (int i = 1; i <= N; ++i)
	{
		int a;
		while (cin >> a && a)
			G[i].push_back(a);
	}
	
	// scc缩点处理 
	for (int i = 1; i <= N; ++i)
		if (!dfn[i])
			tarjan(i);
			
	// 计算出入度
	for (int i = 1; i <= N; ++i)
	{
		for (int j = 0; j < G[i].size(); ++j)
		{
			int v = G[i][j];
			if (scc[i] != scc[v])
			{
				++din[scc[v]];
				++dout[scc[i]];	
			}	
		}	
	}
	
	// 计算出入度为零的节点个数
	int a = 0, b = 0;
	for (int i = 1; i <= cnt; ++i)
	{
		if (!din[i])    ++a;
		if (!dout[i])    ++b;
	}
	
	// 问1:入度为0的节点即所求
	cout << a << endl;
	// 问2:要满足题意,则所有节点的出入度都不为0。
	// 要使使用的边最少,则将出度为0的节点指向入度为0的节点。
	// 两种节点的个数相等的情况下,两者的个数即所求。
	// 若不相等,取二者的max。
	if (cnt == 1)    cout << 0 << endl;    // 特判,此时原图就是连通的,不需要添边 
	else    cout << max(a, b) << endl; 
	
	return 0;
}

二、P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G

P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G

1、算法简析

建立有向图模型:奶牛是节点,“喜欢”是有向边。因为强连通分量的定义,所以一个强连通分量中的奶牛都可能是“明星”。因此,我们进行 S C C SCC SCC 缩点处理,使原图变成 D A G DAG DAG 图。此时,若我们选择一个入度为 0 0 0 的节点作为根节点,向上拉直,就形成了一棵树(当然,原图可能是不连通的,所以也可能形成森林)。显然,树(森林)的叶子节点就是所求。换句话说,也就是出度为 0 0 0 S C C SCC SCC 中的节点即所求。

需要注意的是,若出度为 0 0 0 S C C SCC SCC 的个数大于 1 1 1,则满足条件的节点个数为 0 0 0。因为“明星奶牛”需要能被所有节点访问,若存在其它节点的出度为 0 0 0,显然就不能满足要求。也就是说,形成的树(森林)的叶子节点只能有一个。或者,出度为 0 0 0 S C C SCC SCC 的个数只能为 1 1 1

2、Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll quickin(void)
{
	ll ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 1e4 + 3;
int N, M;
vector<int> G[MAX];
int dfn[MAX], low[MAX], tot;
stack<int> S;
bool instk[MAX];
int scc[MAX], siz[MAX], cnt;
int dout[MAX];

void tarjan(int u)
{
	dfn[u] = low[u] = ++tot;
	S.push(u), instk[u] = true;
	
	for (int i = 0; i < G[u].size(); ++i)
	{
		int v = G[u][i];
		if (!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (instk[v])
			low[u] = min(low[u], dfn[v]);
	}
	
	if (dfn[u] == low[u])
	{
		int t;
		++cnt;
		do
		{
			t = S.top();
			S.pop(), instk[t] = false;
			scc[t] = cnt;
			++siz[cnt];
		} while (t != u);
	}
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	N = quickin(), M = quickin();
	for (int i = 0; i < M; ++i)
	{
		int a, b;
		a = quickin(), b = quickin();
		G[a].push_back(b);
	}
	
	for (int i = 1; i <= N; ++i)
		if (!dfn[i])
			tarjan(i);
			
	for (int i = 1; i <= N; ++i)
	{
		for (int j = 0; j < G[i].size(); ++j)
		{
			int v = G[i][j];
			if (scc[i] != scc[v])
			{
				++dout[scc[i]];
			}
		}
	}
	
	int sum = 0, zeros = 0; // sum -- 出度为0的SCC包含的节点个数; zeors -- 出度为0的SCC个数
	for (int i = 1; i <= cnt; ++i)
	{
		if (!dout[i])
		{
			sum += siz[i];
			++zeros;
		}
	}
	
	if (zeros > 1)    sum = 0; // 特判:若存在两个及以上的SCC出度为0,它们肯定无法相互访问,都不满足要求 
	cout << sum << endl;
	
	return 0;
}

三、P3387 【模板】缩点

P3387 【模板】缩点

1、算法简析

对于本题,我们可以先进行缩点,建立一张新的 D A G DAG DAG 图,然后在新图上寻找最大的权值之和。

注意, S C C SCC SCC 缩点后,新节点的编号满足拓扑序列。因此,可以用动态规划求最大值。

2、Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

ll quickin(void)
{
	ll ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MAX = 1e4 + 3;
int N, M, worth[MAX];
vector<int> G[MAX];
int dfn[MAX], low[MAX], tot;
stack<int> S;
bool instk[MAX];
int scc[MAX], cnt;
int nworth[MAX];         // 新图中各节点的权值 
vector<int> nG[MAX];     // 新图中的边 
int dp[MAX];             // dp[u] -- 以u为起点的路径的最大值 

void tarjan(int u)
{
	dfn[u] = low[u] = ++tot;
	S.push(u), instk[u] = true;
	
	for (int i = 0; i < G[u].size(); ++i)
	{
		int v = G[u][i];
		if (!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (instk[v])
			low[u] = min(low[u], dfn[v]);
	}
	
	if (dfn[u] == low[u])
	{
		int t;
		++cnt;
		do
		{
			t = S.top();
			S.pop(), instk[t] = false;
			scc[t] = cnt;
		} while (t != u);
	}
}

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	N = quickin(), M = quickin();
	for (int i = 1; i <= N; ++i)
		worth[i] = quickin();
	for (int i = 0; i < M; ++i)
	{
		int a, b;
		a = quickin(), b = quickin();
		G[a].push_back(b);
	}
	
	for (int i = 1; i <= N; ++i)
		if (!dfn[i])
			tarjan(i);
			
	for (int u = 1; u <= N; ++u)
	{
		nworth[scc[u]] += worth[u];              // 新节点的权值 
		for (int i = 0; i < G[u].size(); ++i)
		{
			int v = G[u][i];
			if (scc[u] != scc[v])                // 存新边 
				nG[scc[u]].push_back(scc[v]);
		}
	}
	
	// SCC缩点后的新节点的编号按降序满足拓扑序列
	for (int u = 1; u <= N; ++u)
	{
		if (dp[u] == 0)    dp[u] = nworth[u];

		for (int i = 0; i < nG[u].size(); ++i)
		{
			int v = nG[u][i];
			dp[u] = max(dp[u], dp[v] + nworth[u]);
		}
	}
	
	int ans = 0;
	for (int i = 1; i <= cnt; ++i)
		ans = max(ans, dp[i]);
		
	cout << ans << endl; 
	
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

浅谈Windows 上的线程亲和性(Thread affinity)

​ 前言 线程属性包括是否分离、亲和性、调度策略和优先级等。Linux默认的调度策略是CFS(完全公平调度算法),而 Windows 是基于优先级抢占式的策略。 在这些方面,Windows 和 Linux 差异巨大。本文仅针对 Windows 系统的线程亲和性进行探讨。 线程亲和性(Thread affinity) 什…

解锁AI的神秘力量:LangChain4j带你步入智能化实践之门

关注微信公众号 “程序员小胖” 每日技术干货&#xff0c;第一时间送达&#xff01; 引言 在数字化转型的浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;正逐渐成为推动企业创新和增长的关键力量。然而&#xff0c;将AI技术融入到日常业务流程并非易事&#xff0c;它…

谷歌月球模型

收费产品&#xff0c;白嫖党勿扰 收费金额500元 1 概述 前些时间&#xff0c;有个客户&#xff0c;想fight TAIWAN&#xff0c;于是乎&#xff0c;我把谷歌地球整个台湾的模型都下载下来了&#xff0c;大约300GB。今天&#xff0c;又有个客户&#xff0c;提出一个过分要求&…

【第14章】spring-mvc之ajax

文章目录 前言一、准备二、单个值1.前端2.后端3. 结果 三、对象1.前端2.后端3. 结果 四、JSON对象1.前端2.后端3. 结果 五、JSON数组1.前端2.后端3. 结果 总结 前言 AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是一种用于创建快速动态网页的技术&#xff0c…

STM32:GPIO输入输出

文章目录 1、GPIO介绍1.1 GPIO的基本结构1.1 GPIO的位结构 2、 GPIO工作模式3、GPIO标准外设库接口函数3.1 RCC接口函数3.2 GPIO接口函数3.2.1 GPIO的读取函数3.2.1 GPIO的写入函数 4、GPIO的初始化 1、GPIO介绍 GPIO&#xff08;General Purpose Input Output&#xff09;通用…

深入大模型量化技术,大模型端侧落地已Ready?

揭秘未来&#xff1a;大模型量化技术如何革新移动AI应用 ©作者|饮水机 来源|神州问学 前言 最近&#xff0c;苹果发布了OpenELM系列模型&#xff0c;参数规模分别为270M、450M、1.1B和3B。与此同时&#xff0c;微软也推出了Phi-3系列模型&#xff0c;其中mini版本的参数…

支付时,中国网联结算与中国银联结算的区别与联系

随着电子商务和互联网支付的快速发展&#xff0c;中国的支付清算市场也呈现出前所未有的繁荣景象。在这个大背景下&#xff0c;中国网联与中国银联作为两大支付清算机构&#xff0c;各自扮演着重要的角色。本文将对两者的区别和联系进行深入探讨&#xff0c;以期对读者有更全面…

【北京迅为】《iTOP-3588开发板快速烧写手册》-第9章ubuntu系统下升级固件

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

智慧公厕,城市现代化公卫变革的关键节点

随着城市的快速发展&#xff0c;公共厕所作为社会基础民生设施&#xff0c;正越来越受到精细化管理的重视。智慧公厕的出现&#xff0c;为传统公共厕所的脏乱臭提供了解决方案&#xff0c;通过物联网、大数据、云计算、自动化控制等先进技术的贡献&#xff0c;使公厕管理更加高…

怎么编辑百度百科个人词条

辑百度百科个人词条是一个相对复杂的过程&#xff0c;需要遵循一定的步骤和规则。以下是百科优化网整理的编辑百度百科个人词条的步骤和注意事项。 1. 确定编辑资格 百度百科个人词条的编辑权主要赋予那些具有一定影响力的公众人物&#xff0c;或者是有一定“身份”的人物&…

大模型驱动的新一代 BI 平台,Sugar BI 开启智慧决策新模式

本文整理自 2024 年 4 月 16 日的 2024 百度 Create 大会上的《大模型驱动的新一代 BI 平台如何开启智慧决策》分享。 全文包括了可视化 BI 分析技术架构、智能图表推荐策略与规则设计、Sugar Bot 智能问数的技术实现流程&#xff0c;以及目前的场景应用等。 1 Sugar BI 产…

【C语言】路漫漫其修远兮,深入[指针]正当下

一. 指针初步 1.概念定义 地址&#xff1a;我们在内存中开辟空间时&#xff0c;为了方便后续访问&#xff0c;每个数据有确切的地址。 指针&#xff1a;指向数据的地址&#xff0c;并将其地址储存在指针变量中。 2.基本运算符 • 取地址操作符&#xff08;&&#xff09; …

OpenHarmony 4.0 实战开发——分布式软总线解析:设备发现与传输

OpenHarmony 的分布式软总线子系统为 OpenHarmony 系统提供的通信相关的能力&#xff0c;包括&#xff1a;WLAN 服务能力、蓝牙服务能力、软总线、进程间通信 RPC&#xff08;Remote Procedure Call&#xff09;等通信能力。 其中主要包括&#xff1a; WLAN 服务&#xff1a;…

【Java开发的我出书啦,各位同仁快过来围观】!!!

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容出书的目的出书的过程书籍的内容 &#x1f4e5;博主的话 &#x1f50a;博主介绍 文章目录 &#x1f50a;博主介绍&#x1f964;本文内容出书的目的出书的过程书籍的内容 &#x1f4e5;博主的话 &#x1f33e;阅读前&#x…

机器学习 | 时间序列预测中的AR模型及应用

自回归模型&#xff0c;通常缩写为AR模型&#xff0c;是时间序列分析和预测中的一个基本概念。它们在金融、经济、气候科学等各个领域都有广泛的应用。在本文中&#xff0c;我们将探索自回归模型&#xff0c;它们如何工作&#xff0c;它们的类型和实际例子。 自回归模型 自回…

Elasticsearch中的三种分页策略深度解析:原理、使用及对比

码到三十五 &#xff1a; 个人主页 在Elasticsearch中&#xff0c;分页是查询操作中不可或缺的一部分。随着数据量的增长&#xff0c;如何高效地分页查询数据急需需要面对的问题。Elasticsearch提供了三种主要的分页方式&#xff1a;from size、scroll和search_after。下面详细…

ICode国际青少年编程竞赛- Python-2级训练场-基础训练4

ICode国际青少年编程竞赛- Python-2级训练场-基础训练4 1、 for i in range(4):if i > 2:Flyer[i].step(3)else:Flyer[i].step(1) Dev.step(Item[3].x - Dev.x)2、 for i in range(6):if i < 3:Flyer[i].step(2)else:Flyer[i].step(3) Dev.step(Item[2].x - Dev.x)3、 …

制造版图大变革!逾10座晶圆厂蓄势待发 | 百能云芯

在全球半导体产业的激烈竞争和市场需求的复杂波动中&#xff0c;晶圆厂建设热潮正在美国兴起&#xff0c;这一波建设浪潮的核心动力之一&#xff0c;便是美国政府推出的《芯片与科学法案》所承诺的巨额补贴&#xff0c;旨在提升美国在全球半导体行业的竞争力。 当地时间4月25日…

翻译《The Old New Thing》 - The new scratch program

The new scratch program - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050422-08/?p35813 Raymond Chen 2005年4月22日 译注&#xff1a;此篇是 翻译《The Old New Thing》 - The scratch program 姊妹篇&#xff0c;对 scratch 程序作…

普通人副业要趁早,5种靠谱且持久的赚钱副业

中年危机、35岁被裁&#xff0c;这些听起来就让人焦虑的词汇&#xff0c;是否也让你感到不安&#xff1f;别担心&#xff0c;只要你早早开启副业之旅&#xff0c;这些都不是问题。 今天&#xff0c;我要为你介绍的这5种副业&#xff0c;不仅能帮你赚钱&#xff0c;还能让你的能…
最新文章