题目描述

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

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

解析

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

咱写挂了(哭)。

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

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

这道题需要分类讨论。

  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. kexue shangwang

    根据实践,pptp.IPsec甚至OpenVPN等kexue上网法已经无法顺利翻越GFW.通过抓包可知,GFW会将pptp的握手期间的ack包吞掉,导致本地一直无法收到服务器端的响应.而OpenVPN ...

  2. mysql查询之 用户行程的取消率,人流量高峰时段

    1.用户行程的取消率 Trips 表中存所有出租车的行程信息.每段行程有唯一键 Id,Client_Id 和 Driver_Id 是 Users 表中 Users_Id 的外键.Status 是枚举类 ...

  3. Legacy和UEFI,MBR和GPT的区别

    Legacy(历史的,遗留的,传统的)和UEFI指的是系统引导方式(Legacy为传统BIOS,UEFI为新式BIOS),MBR和GPT指的是磁盘分区表类型. 一般情况下都是Legacy+MBR, U ...

  4. Java环境配置-jdk和jre的安装

    java 是直接在 jdk 下就可以运行 jdk会自带jre 所以只需要下载jdk配置一下环境就可以了 一般编辑java是需要 myeclipse 也可以用 记事本TXT文档 或者用 notepad+ ...

  5. python爬虫scrapy(一)

    一,准备scrapy依赖组件环境,按照以下顺序安装 .wheel pip install wheel .lxml http:.PyOpenssl https://pypi.python.org/pyp ...

  6. 数列分段 II

    题目描述 思路 代码 #include <cstdio> int n, m, arr[100005], ans; int l, r, mid, inf = 0x7f3f3f3f; inli ...

  7. prometheus+alertmanager+granafa监控总结,安装基于docker-compose(长期更新)

    最近自己个人尝试在使用prometheus+grafana监控工作业务上的指标, 但是报警功能还没有实际用上,但是感觉是很好用,写下一些啃prometheus官网文档并且自己用到的一些配置的总结,后续 ...

  8. html中实现某区域内右键自定义菜单

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 创建包含CRUD操作的Web API接口-第一部

    在这里,我们将创建一个新的Web API项目,它将使用实体框架实现Get,POST.PUT和DELETE方法来实现CRUD操作. 首先,在Visual Studio 2013 for Web expr ...

  10. 使用Jenkins自带功能(不用shell)构建Docker镜像并推送到远程仓库

    意义: 一开始实现这个目的是在Jenkins中使用的shell脚本,也就是如下的这个: bash # 进入到生成jar包的根目录 cd ${WORKSPACE}/${module_filename} ...