题目描述

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

请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

解析

这道题不错,很考验思考问题的全面性,而且代码写起来似乎也比较坑。

咱写挂了(哭)。

乍一看似乎第一问就是要我们求连通块个数,第二问就是要我们求每个连通块中点的个数。

对,但这只是一小部分,我们少考虑了一些东西。

这道题需要分类讨论。

  1. 如果某个连通块一个割点都没有会怎么样?那么在这个子图中,我们在任意两个位置设置出口即可,对于该连通块,若其包含\(x\)个点,其方案数为\(x(x-1)/2\)。
  2. 如果某个连通块只有一个割点,我们在此连通块的任意一点都可以放置出口,并统计方案数。
  3. 特别特别需要注意的一个坑点,我们在考虑设置出口时,要知道此题只会出现一个坍塌的挖煤点!所以,如果某个连通块有两个及以上个割点,其还是可以与其它连通块相连,所以这个连通块中是不必设置出口的!

这题最核心的一点就是要注意到只会出现一个坍塌点,所以任何时候我们都只用考虑只有一个割点时的情况。

提一些细节,在dfs划分连通块时,我们不能只记某个点是否到达过,我们得记它属于哪个连通块,否则会少算一些或者是算重复一些(这个还要看你怎么写)。

为什么要提呢,因为我写错了,我甚至还没有注意到只会出现一个坍塌点。

参考代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define N 501
using namespace std;
inline ll read()
{
ll f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct rec{
int next,ver;
}g[N*N];
ll head[N],tot,n,m,low[N],dfn[N],cnt,root,c[N],num,k,now;
ll ans1,ans2;
bool cut[N];
ll v[N];
inline void add(int x,int y)
{
g[++tot].ver=y;
g[tot].next=head[x],head[x]=tot;
}
inline void tarjan(int x)//tarjan求割点板子
{
low[x]=dfn[x]=++cnt;
int flag=0;
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]){
flag++;
if(x!=root||flag>1) cut[x]=1;
}
}
else low[x]=min(low[x],dfn[y]);
}
}
inline void dfs(int x)
{
v[x]=num;++k;//划分连通块num,统计该连通块中点的个数k
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(v[y]!=num&&cut[y]) v[y]=num,now++;//这里卡了我许久,这样写才能避免重复计算该连通块包含割点数量
if(!v[y]) dfs(y);
}
}
int main()
{
int kase=0;
while(~scanf("%d",&n)&&n){
memset(head,0,sizeof(head));
memset(cut,0,sizeof(cut));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(v,0,sizeof(v));
tot=ans2=1;ans1=m=0;
for(int i=1;i<=n;++i){
ll u,v;
u=read(),v=read();
add(u,v),add(v,u);
m=max(m,max(v,u));
}
cnt=num=0;
for(int i=1;i<=m;++i)
if(!dfn[i]) root=i,tarjan(i);
for(int i=1;i<=m;++i)
if(!v[i]&&!cut[i]){
k=now=0,num++;
dfs(i);
if(now==0){//注意,这里是重点
ans1+=2;
ans2*=(k-1)*k/2;
}
if(now==1) ans1++,ans2*=k;
}
printf("Case %d: %lld %lld\n",++kase,ans1,ans2);
}
return 0;
}

P3225 [HNOI2012]矿场搭建[割点]的更多相关文章

  1. P3225 [HNOI2012]矿场搭建 割点 tarjan 双联通分量

    https://www.luogu.org/problemnew/show/P3225 题意 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条 ...

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

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

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

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

  4. P3225 [HNOI2012]矿场搭建 tarjan割点

    这个题需要发现一点规律,就是先按割点求块,然后求每个联通块中有几个割点,假如没有割点,则需要建两个出口,如果一个割点,则需要建一个出口,2个以上不用建. 题干: 题目描述 煤矿工地可以看成是由隧道连接 ...

  5. P3225 [HNOI2012]矿场搭建 题解

    这道题挺难的,可以加深对割点的理解,还有,排列组合好重要了,分连通块,然后乘法原理(加法原理计数什么的) 传送门   https://www.luogu.org/problem/P3225 省选oi题 ...

  6. 洛谷P3225 HNOI2012 矿场搭建

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

  7. 洛谷 P3225 [HNOI2012]矿场搭建

    传送门 题目大意:建设几个出口,使得图上无论哪个点被破坏,都可以与出口联通. 题解:tarjian求割点 首先出口不能建在割点上,找出割点,图就被分成了几个联通块. 每个联通块,建出口.如果割点数为0 ...

  8. P3225 [HNOI2012]矿场搭建

    传送门 对于一个点双联通分量,如果它连接了两个或更多割点 那么不论哪个点GG都有至少一条路通到其他的点双联通分量,所以我们不用考虑 如果它只连接一个割点,如果这个割点GG,那整个块也一起GG,所以要再 ...

  9. [Luogu] P3225 [HNOI2012]矿场搭建

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

随机推荐

  1. junit单元测试不通过报documentationPluginsBootstrapper相关异常

    这是因为Spring整合springfox-swagger2后导致的,错误信息如下: -- ::, [main] [WARN] [org.springframework.context.support ...

  2. Python开发之virtualenv和virtualenvwrapper详解

    在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题: 亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难. 此时,我们需要对于不同的工程使用 ...

  3. SQL 向表中添加字段

    如果要在数据表中添加一个字段,应该如何表示呢?下面就为您介绍表添加字段的SQL语句的写法,希望可以让您对SQL语句有更深的认识. 通用式: alter table [表名] add [字段名] 字段属 ...

  4. My Swift Study

    参考资源 <swifter> https://github.com/iOS-Swift-Developers/Swift 闭包逃逸 swift3中,闭包默认是非逃逸的.如果一个函数参数可能 ...

  5. AX 2009中Set运用

    Set运行: 例子: Set m_set = new Set(Types::String); m_set.add("AAA"); m_set.add("BBB" ...

  6. PXC增量恢复添加节点(IST)

    绕开SST通过IST方式添加Node到Percona XtraDB Cluster  Gcache存储了所有的  writeset ,因此说这个集合的大小直接决定了允许其他节点宕机后多长时间内可以进行 ...

  7. c#部分类

    c#提供了一个部分类,它只显示类的一部分,用关键字partical修饰 using System; public partial class Course { public int Id { get; ...

  8. [C#] 匿名方法的方便和安全

    static void Main(string[] args) { int count = 5; //不安全写法 Task.Run(() => { Thread.Sleep(1000); Con ...

  9. 【洛谷 P1659】 [国家集训队]拉拉队排练(manacher)

    题目链接 马拉车+简单膜你 #include <cstdio> #include <cstring> #include <algorithm> using name ...

  10. 提高QPS

    常用方案 1.异步化+MQ 即非阻塞,化繁为简,拿到你需要处理的资源后尽快回复.适用于事务处理场景,且无需对上游返回数据场景. 2.无锁设计 本质上是要降低锁冲突,基于数据版本的乐观锁 有效的减少了互 ...