https://www.luogu.org/problem/P3225

这个东西有点绕。

最平凡的情况,整个原图只有一个点,那么它坍塌了之后就没有点了,不需要进行任何逃生。否则,当一个点坍塌之后,每个其他点的工人都要逃向逃生出口。

首先把双连通分量缩点,缩点完成之后必定是一片森林,树与树之间是乘法原理。

单独考虑一棵树。

平凡的情况,只有一个根节点,没有边。

这种情况下,假如原图中该双连通分量中有>=2个点,则这个双连通分量中要建立2个出口(其中一个出口坍塌了,都可以从另一个出口走),否则假如只有一个点,则只需要建立1个出口。

不平凡的情况,是一棵无根树。必定存在叶子,每个叶子都必须建立1个出口。这个出口必须建立在非原图割点的位置,假如原图这个双连通分量没有割点(这个双连通分量只有一个点,去掉都没没事),则不需要加。

不是叶子的情况,当其他节点坍塌,则必定可以去到至少1个叶子节点逃生,不需要建立逃生出口。当自己(且自己只有一个点)坍塌,每个子树自己跑去自己的叶子就可以了。

那么先特判掉n=1的情况。然后在原图中跑出原图的割点。然后遍历一遍原图的点,从没有被访问过的非割点进入,搜索连接的所有非割点,这些非割点都属于这个双连通分量,而搜索到的割点也属于这个双连通分量不过不需要进去。这样会漏掉两个割点之间的所有非割点和割点,不过这貌似没有问题?因为假如都有两个非割点了,答案就是0了。而且环的另一个半(或者1/3,或者1/4)也会搜索到那两个割点的,反正都是0。

假如只有一个割点,则这个是缩点后图的叶子,贡献C(非割点数量,1)。

假如有多于两个割点,则不贡献,少数的非割点和割点都无所谓了

假如没有割点,则这个双连通分量缩点之后只剩下自己一个点作为树,那么也是贡献C(非割点数量,2),(当该双连通分量有多于两个点时),或者0(当该双连通分量只有1个点时)。

各个双连通分量之间选点独立,各个树之间选点独立,全部乘法叠加。

从这道题可以得到一个常识:每个割点不一定仅属于一个双连通分量,比如一个dio型图。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int MAXN = 505; int n;
vector<int> G[MAXN]; int dfn[MAXN], low[MAXN], dfncnt;
bool cut[MAXN];
int vis[MAXN], viscol;
int cntcut, cntncut; void init() {
for(int i = 1; i <= 500; ++i)
G[i].clear();
dfncnt = 0;
memset(cut, false, sizeof(cut));
memset(vis, false, sizeof(vis));
memset(dfn, false, sizeof(dfn));
memset(low, false, sizeof(low));
viscol = 1;
} void tarjan(int u, int p) {
low[u] = dfn[u] = ++dfncnt;
ll sum = 0;
int ch = 0;
for(auto v : G[u]) {
if(!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(p == -1)
ch++;
else if(low[v] >= dfn[u])
cut[u] = true;
} else
low[u] = min(low[u], dfn[v]);
}
if(ch >= 2)
cut[u] = true;
} void dfs(int u, int p) {
//cout << "u=" << u << endl;
vis[u] = viscol;
++cntncut;
for(auto v : G[u]) {
if(vis[v] != viscol) {
vis[v] = viscol;
if(cut[v])
++cntcut;
else
dfs(v, u);
}
}
} int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int m, kase = 1;
while(~scanf("%d", &m)) {
if(m == 0)
return 0;
init();
n = 0;
for(int i = 1, u, v; i <= m; ++i) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
n = max(n, max(u, v));
}
for(int i = 1; i <= n; ++i) {
if(!dfn[i])
tarjan(i, -1);
/*if(cut[i])
printf("cut=%d\n",i);*/
}
unsigned long long sum1 = 0;
unsigned long long sum2 = 1;
for(int i = 1; i <= n; ++i) {
if(!vis[i] && !cut[i]) {
//cout<<"viscol="<<viscol<<endl;
cntcut = cntncut = 0;
dfs(i, -1);
if(cntcut == 0) {
if(cntncut >= 2) {
sum1 += 2;
sum2 *= cntncut * (cntncut - 1) / 2;
} else {
sum1 += 1;
}
} else if(cntcut == 1) {
++sum1;
sum2 *= cntncut;
} else
;
viscol++;
}
}
printf("Case %d: %llu %llu\n", kase++, sum1, sum2);
}
return 0;
}

洛谷 - P3225 - 矿场搭建 - 双连通分量的更多相关文章

  1. BZOJ2730:[HNOI2012]矿场搭建(双连通分量)

    Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一 ...

  2. Tarjan 点双+割点+DFS【洛谷P3225】 [HNOI2012]矿场搭建

    P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤 ...

  3. 洛谷 P3225 [HNOI2012]矿场搭建 解题报告

    P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤 ...

  4. 洛谷——P3225 [HNOI2012]矿场搭建

    P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤 ...

  5. 【洛谷P3225】[HNOI2012]矿场搭建

    矿场搭建 题目链接 根据题意,发生事故时会有一个挖煤点坍塌, 只有当这个点是割点,会对图的连通性产生影响, 我们首先Tarjan一遍找到所有割点,将原图除去这些割点后, 遍历一遍,找出所有连通块,分三 ...

  6. Solution -「洛谷 P5827」边双连通图计数

    \(\mathcal{Description}\)   link.   求包含 \(n\) 个点的边双连通图的个数.   \(n\le10^5\). \(\mathcal{Solution}\)    ...

  7. Solution -「洛谷 P5827」点双连通图计数

    \(\mathcal{Description}\)   link.   求有 \(n\) 个结点的点双连通图的个数,对 \(998244353\) 取模.   \(n\le10^5\). \(\mat ...

  8. 洛谷P3225 HNOI2012 矿场搭建

    题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之 ...

  9. 洛谷—— P3225 [HNOI2012]矿场搭建

    https://www.luogu.org/problem/show?pid=3225 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有 ...

随机推荐

  1. 在Windows QT下使用ZeroMQ

    zeroMQ作为一个嵌入式消息队列系统,以其轻便灵活的使用方式,极为适合应用程序分布式通讯处理, 或者是一种有效的代替常规saocket通讯的方法. 1)下载地址:http://zeromq.org/ ...

  2. SRM331-CarolsSinging(暴力,位运算)

    Problem Statement When the Christmas dinner is over, it's time to sing carols. Unfortunately, not al ...

  3. Jmeter -- 同步定时器

    作用: 模拟并发. 设置一个阀值(请求数量),当请求数达到这个阀值时,允许请求同时发出.例如:想测试一座桥的并发(忽略载重等其他因素,只考虑通过),那么并发的请求就是类似于多少辆车可同时通过桥,而车辆 ...

  4. linux系统基础优化及高级操作命令

    Linux基础系统优化 引言没有,只有一张图. Linux的网络功能相当强悍,一时之间我们无法了解所有的网络命令,在配置服务器基础环境时,先了解下网络参数设定命令. ifconfig 查询.设置网卡和 ...

  5. Oracle三种分页?

    ①select * from (select employee.*, rownum r from employee) where r between 2 and 5; ②select * from ( ...

  6. ThreadPool用法与优势

    1.  线程池的优点: 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执 ...

  7. C++入门经典-例4.5-利用循环求n的阶乘

    1:代码如下: // 4.5.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using ...

  8. 对于Java培训出身的同学,接下来该怎么学习技术?

    首先恭喜从培训班出来找到工作的同学,确实挺不容易的,4个月的培训,每天从早上9点到晚上9点,也是996,主要的活动地方就是宿舍和教室, 让我现在也去培训,我估计还熬不下来. 尤其是对于从小白开始的同学 ...

  9. AXIS2 通过 WSDL生成JAVA文件

    有时在我们的开发中可能会有这种情况就是你要使用webservice但是对方没有给你提供java文件,可能就只会给你一个wsdl文件,这种文件和xml文件是比较相似.axis2也给我们提供了很好的工具如 ...

  10. orcal 中的orcal用法

    ROWID是数据的详细地址,通过rowid,Oracle可以快速的定位某行具体的数据的位置. ROWID可以分为物理rowid和逻辑rowid两种.普通的堆表中的rowid是物理rowid,索引组织表 ...