题意概述:

  一张有向图,在其中设置一些关键点(即题目中的逃生出口),使得删除任意一个点之后其余点都可以到达至少一个关键点。

  问至少需要设置多少中关键点,有多少种设置方法。

解析:

  首先,这道题要求删掉一个点,不难想到这道题与割点有关。其次,删掉一个点其他点仍然可以到达关键点就可以想到是点双联通分量。

  但是,问题关键是,真的需要在每一个点双联通分量中都设置一个关键点吗?

  

答案是否定的,因为如果一个双联通分量连接了两个或两个以上的割点,一个割点被删掉那么还可以通过另外的割点到达某个关键点,如上图,红色点为割点,灰底色的边为割边

所以只需统计含割点个数小于等于1的块数就是最少的关键点个数,如此,则放置关键点的方案数为各个被统计的块(割点数小于等于1的块)的点的个数的乘积,当然,若只找到了一个满足条件的块,那最少关键点数为2,方案数为(令n为点的个数):  n*(n-1)/2.

需要注意的是这道题的数据规模:有500条边,但是并没有对点的编号的说明,所以点的标号可以是任意的,故此题建议离散化,但是我还是偷了个懒,因为数据中的点好像不超过50000

代码如下:

 #include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <vector> using namespace std; //#define File
//#define Debug struct Edge
{
int to;
int next;
}e[]; int n,cnt,cnt_blocks,bcc_cnt,top,Ans,kase;
int p[],dfn[],nbcc[]; long long Sum; pair<int,int> st[];
vector<int> bcc[]; bool cut[]; inline void Add_edge(const int x,const int y)
{
e[++cnt].to=y;
e[cnt].next=p[x];
p[x]=cnt;
return ;
} int Tarjan(const int S,const int fa)
{
int child,lowu,lowv,v,i; dfn[S]=lowu=++cnt_blocks;
child=; for(i=p[S];i;i=e[i].next)
{
v=e[i].to;
if(!dfn[v])
{
st[++top]=make_pair(S,v);
child++;
lowv=Tarjan(v,S);
lowu=min(lowv,lowu);
if(lowv>=dfn[S])
{
cut[S]=true;
bcc_cnt++;
bcc[bcc_cnt].clear();
while(true)
{
if(nbcc[st[top].first]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(st[top].first);
nbcc[st[top].first]=bcc_cnt;
}
if(nbcc[st[top].second]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(st[top].second);
nbcc[st[top].second]=bcc_cnt;
} if(st[top].first==S && st[top].second==v)
{top--;break;}
top--;
}
}
}
else if(dfn[v]<dfn[S] && v!=fa)
{
st[++top]=make_pair(S,e[i].to);
lowu=min(lowu,dfn[v]);
}
} if(fa< && child==)cut[S]=false;
return lowu;
} inline void Init()
{
/*int n,cnt,cnt_blocks,bcc_cnt,top,Ans,kase;
int p[51000],dfn[51000],nbcc[51000]; long long Sum; pair<int,int> st[51000];
vector<int> bcc[1100]; bool visited[51000],cut[51000];*/
cnt=cnt_blocks=bcc_cnt=top=Ans=;
Sum=;
memset(p,,sizeof(p));
memset(dfn,,sizeof(dfn));
memset(nbcc,,sizeof(nbcc));
memset(cut,,sizeof(cut));
for(int i=;i<=;++i)
bcc[i].clear();
memset(st,,sizeof(st));
return ;
} int main()
{
#ifdef File
freopen("2730.in","r",stdin);
#ifndef Debug
freopen("2730.out","w",stdout);
#endif
#endif int i,j,x,y,cut_cnt; while(~scanf("%d",&n) && n)
{
Init();
for(i=;i<=n;++i)
{
scanf("%d%d",&x,&y);
Add_edge(x,y);
Add_edge(y,x);
} for(i=;i<=n;++i)
{
if(!dfn[i])Tarjan(i,-);
} for(i=;i<=bcc_cnt;++i)
{
cut_cnt=;
for(j=;j<(int)bcc[i].size();++j)
{
if(cut[bcc[i][j]])cut_cnt++;
}
if(cut_cnt==)
{
Ans++;
Sum*=(long long)(bcc[i].size()-cut_cnt);
}
} if(bcc_cnt==)
{
Ans=;
Sum=bcc[].size()*(bcc[].size()-)/;
} printf("Case %d: %d %lld\n",++kase,Ans,Sum);
} #ifdef File
fclose(stdin);
#ifndef Debug
fclose(stdout);
#endif
#endif return ;
}

BZOJ2730 矿场搭建 解题报告 点双联通分量的更多相关文章

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

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

  2. BZOJ_2730_ [HNOI2012]矿场搭建_点双联通分量

    BZOJ_2730_ [HNOI2012]矿场搭建_点双联通分量 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路 ...

  3. bzoj 2730: [HNOI2012]矿场搭建——tarjan求点双

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

  4. 『Tarjan算法 无向图的双联通分量』

    无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...

  5. 【UVA10972】RevolC FaeLoN (求边双联通分量)

    题意: 给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通. 分析: 这题的解法还是很好想的.先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans ...

  6. lightoj 1300 边双联通分量+交叉染色求奇圈

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1300 边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点.这题只要求在 ...

  7. HDU5409---CRB and Graph 2015多校 双联通分量缩点

    题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分 ...

  8. poj2942(双联通分量,交叉染色判二分图)

    题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1.2.总人数为奇数.3.有仇恨的骑士不能挨着坐.问有几个骑士不能和任何人形成任何的圆圈. 思路:首先 ...

  9. 大白书中无向图的点双联通分量(BCC)模板的分析与理解

    对于一个无向图,如果任意两点至少存在两条点不重复(除起点和终点外无公共点)的路径,则这个图就是点双联通. 这个要求等价于任意两条边都存在于一个简单环(即同一个点不能在圈中出现两次)中,即内部无割点. ...

随机推荐

  1. linux下的so、o、lo、a、la文件的区别

    o: 编译的目标文件a: 静态库,其实就是把若干o文件打了个包so: 动态链接库(共享库) lo: 使用libtool编译出的目标文件,其实就是在o文件中添加了一些信息la: 使用libtool编译出 ...

  2. ASP.NET MVC5 之路由器

    这篇博客介绍的很详细 http://www.cnblogs.com/yaozhenfa/p/asp_net_mvc_route_1.html

  3. hcode视频教程中心(学习h5和hbuilder等)

    网站: http://www.hcoder.net/course

  4. 343 Integer Break 整数拆分

    给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积.例如,给定 n = 2,返回1(2 = 1 + 1):给定 n = 10,返回36(10 = 3 ...

  5. 315 Count of Smaller Numbers After Self 计算右侧小于当前元素的个数

    给定一个整型数组 nums,按要求返回一个新的 counts 数组.数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于nums[i] 的元素的数量.例子:给定 nu ...

  6. 大数据~说说Hadoop

    Hadoop是一个由Apache基金会所开发的分布式系统基础架构. 用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力进行高速运算和存储.  Hadoop实现了一个分布式文件系 ...

  7. 6.10---springboot的配置

  8. jQuery文档就绪

    很多jQuery代码都有如下片段: $(document).ready(function(){ //代码 }) 作用就是等文档结构加载完成后再去执行function中的代码,功能类似于window.o ...

  9. git使用原理

    如果需要新建仓库: mkdir new_artcle//artcle为文件名 cd new_artcle//进入该目录 git init //初始化工作空间 git add 文件名(article) ...

  10. 微信小程序php后台实现

    这里简单介绍用php后台实现获取openid并保存到数据库: 微信的登陆流程是这样的 首先前端发送请求到服务器: wx.login({ success: function (res) { var co ...