当前位置: 首页 > news >正文

信息学奥赛一本通 1525:电力 | OpenJudge 百练 2117:Electricity

【题目链接】

ybt 1525:电力
OpenJudge 百练 2117:Electricity(原英文题)

【题目考点】

1. 图论:割点

【解题思路】

连通块就是连通分量。
首先该题是多组数据问题,注意清空相关变量。输入时边数可能为0,因此需要判断顶点数和边数都为0时,再结束程序。注意输入的顶点编号从0开始,本人习惯从1开始,就将顶点编号都增加1。
输入无向图,该无向图未必是连通的。我们需要先统计出原图连通分量的数量connCnt。尝试以每个顶点为起始顶点调用tarjan,成功调用tarjan进行深搜的次数就是连通分量的数量。
设数组connNum,connNum[u]表示u所在的连通分量在去掉顶点u后会变成几个连通分量。
调用tarjan求割点:
如果顶点u没有邻接点,删掉u后这里会变为0个连通分量,connNum[u]初值设为0。
如果顶点u有邻接点,且不是割点,删掉u后还是有1个连通分量,connNum[u]初值应该设为1。
如果顶点u是割点:

  • 如果u是tarjan调用的起始顶点,即dfs生成树的根结点。将connNum[u]初值设为1,表示去掉u后,u的第一个孩子为根的子树为1个连通分量。当看到u的第2个孩子时会判断u是割点,从这里开始每访问到一个孩子,connNum[u]就增加1。对u的所有孩子访问结束后,connNum[u]为u的孩子数,即子树个数,也就是去掉u后会得到的连通分量的数量。
  • 如果u不是tarjan调用的起始顶点,即不是根结点,那么去掉u后,一定存在一个u的双亲所在的连通分量(u的上方子树),因此将connNum[u]初值设为1。在访问u的孩子v时,如果满足dfn[u] <= low[v],那么去掉顶点u后,以v为根的子树为一个连通分量,connNum[u]计数增加1。

在调用tarjan求出connNum数组以及连通分量数量connCnt后,遍历connNum数组。如果去掉顶点i,则相当于先少1个连通分量,而后增加connNum[i]个连通分量。去掉顶点i后连通分量数量为connCnt-1+connNum[i],求该表达式的最大值即为结果。

【题解代码】

解法1:求割点

#include <bits/stdc++.h>
using namespace std;
#define N 10005
int n, m, connCnt, connNum[N], dfn[N], low[N], ts, root, ans;
vector<int> edge[N];
void tarjan(int u)
{//如果u是根,则先有1个子树是连通分量,从第二个子树开始计数。如果u不是根,则其上方子树算1个连通分量。
	int child = 0;
	connNum[u] = edge[u].empty() ? 0 : 1;//connNum[u]:删掉u后,u所在连通分量变为几个连通分量。如果u没有邻接点,删掉u后就少1个连通分量。 
	dfn[u] = low[u] = ++ts;
	for(int v : edge[u])
	{
		if(dfn[v] == 0)
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
			if(root == u && ++child > 1 || root != u && dfn[u] <= low[v])
				connNum[u]++;//只要u被判断为割点,则一定存在一个子树在删除u后是一个连通分量。
		}
		else
			low[u] = min(low[u], dfn[v]); 
	}
}
int main()
{
	int u, v;
	while(cin >> n >> m && !(n == 0 && m == 0))
	{
		ans = connCnt = ts = 0;
		for(int i = 1; i <= n; ++i)
			edge[i].clear();
		memset(connNum, 0, sizeof(connNum));
		memset(dfn, 0, sizeof(dfn));
		for(int i = 1; i <= m; ++i)
		{
			cin >> u >> v;
			u++, v++;
			edge[u].push_back(v);
			edge[v].push_back(u);
		}
		for(int i = 1; i <= n; ++i) if(dfn[i] == 0)
		{
			connCnt++;//连通分量计数 
			tarjan(root = i);
		}
		for(int i = 1; i <= n; ++i)
			ans = max(ans, connCnt+connNum[i]-1);
		cout << ans << '\n'; 
	}
	return 0;
}

相关文章:

  • Unity NodeCanvas AI使用笔记
  • MR-Flink-Spark任务提交-常用命令
  • Python赋能区块链溯源系统:从技术实现到应用落地
  • VBA技术资料MF281:驱动器列表和类型
  • HarmonyOS开发,解决Kill server failed 报错问题
  • electron 入门
  • Java 异常处理
  • 泰瑞达 ETS-88设备整理
  • 【Java】方法
  • ElasticSearch 7.x 集群 + Kibana 部署完全指南(5节点)
  • 【无标题】RegisterClassObjects
  • 全方位对比oracle18c和oracle 19c
  • 使用码云搭建CocoaPods远程私有库
  • java面试题,什么是动态代理?、动态代理和静态代理有什么区别?说一下反射机制?JDK Proxy 和 CGLib 有什么区别?动态代理的底层
  • List、Set 和 Map 的区别及常见实现类、线程安全集合(总结图表)
  • 【正点原子K210连载】第七十六章 音频FFT实验 摘自【正点原子】DNK210使用指南-CanMV版指南
  • 自学python——第二天:)
  • AI大模型交付业务起势,亚信科技书写AI时代的转型样本
  • 游戏引擎学习第170天
  • 数据结构中的引用管理对象体系
  • 汇源果汁发文:经营情况一切正常
  • 重庆三峡学院回应“中标价85万设备网购300元”:已终止采购
  • 2025年两岸关系研讨会在上海开幕
  • 屈晓华履新四川省社科联党组书记,此前担任省国动办主任
  • 开局良好,我国第一季度广告业务收入保持较快增速
  • 高盛上调A股未来12个月目标点位,沪深300指数潜在回报15%