【题目大意】

煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

【思路】

可以得出这样的结论:

(1)如果一个点是割点,那么在它上面建救援出口是没有意义的

(2)对于出去割点后的连通块,如果它和两个及以上的割点相连,这不需要建救援出口;否则要建一个救援出口,在连通块里选任意一个即可,最终方案数为这些连通块大小的乘积。

(3)如果只有一个联通块,那么至少建两个救援出口,最终方案书为(size)*(size-1)/2。

所以这样做:

首先用tarjan求出割点并记录,然后跑dfs求出除去割点后的连通块的个数和大小,再依据上述结论输出答案。

【错误点】

数组从0开始和从1开始搞错了一次..判断连通块周围割点的个数的时候弄错了…具体见注释

一开始忘记清空vector,后来发现用clear清空的话会RE。请教之后才知道vector清空的正确方式长成这个样子:vector<int>().swap(E[i])

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=+;
vector<int> E[MAXN];
int kase=;
int n,m;//隧道的数量和矿井的数量
int dfn[MAXN],low[MAXN],vis[MAXN];
int cut[MAXN],cnt;//记录每一个点是否是割点以及连通块的总数
int nearcut[MAXN],size[MAXN];//当前连通块可以到达的割点数量&每个连通块的大小
int t;
int viscut[MAXN]; int tarjan(int isrt,int u)
{
vis[u]=;
dfn[u]=low[u]=++t;
int sonnum=;
for (int i=;i<E[u].size();i++)
{
int son=E[u][i];
if (!vis[son])
{
sonnum++;
tarjan(,son);
low[u]=min(low[u],low[son]);
if (isrt && sonnum>=) cut[u]=;//如果是根节点,且孩子的数量大于等于两个,则是割点
if (!isrt && dfn[u]<=low[son]) cut[u]=; //如果不是根节点,并且孩子的low大于等于当前的dfn,即没有走到过u之前,则是割点
}
else
low[u]=min(low[u],dfn[son]);
}
} void dfs(int u)
{
vis[u]=;
size[cnt]++;
for (int i=;i<E[u].size();i++)
{
int son=E[u][i];
if (!vis[son])
if (cut[son])
{
if (viscut[son]!=cnt)
{
//错误点:我一开始直接cnt++了,但是这样是不对的,会导致同一个割点被多次累加
nearcut[cnt]++;
viscut[son]=cnt;
}
}
else dfs(son);
}
} void init()
{
for (int i=;i<MAXN;i++) vector<int>().swap(E[i]);
m=;
for (int i=;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
E[u].push_back(v);
E[v].push_back(u);
m=max(m,max(u,v));//记下总共的矿井数量
}
} void solve()
{
memset(vis,,sizeof(vis));
memset(cut,,sizeof(cut));
memset(size,,sizeof(size));
memset(viscut,,sizeof(viscut));
t=;
for (int i=;i<=m;i++)//错误点:数组都要从1开始
{
if (vis[i]==)
tarjan(,i);//依次找出所有的割点
}
memset(vis,,sizeof(vis));
cnt=;
for (int i=;i<=m;i++)
if (!cut[i] && !vis[i])
{
cnt++;
nearcut[cnt]=;
dfs(i);
}
} void output()
{
printf("Case %d: ",kase);
if (cnt==)
{
printf("2 %lld\n",(long long)m*(m-)/);
return;
} long long tot=;
long long ans=;
if (cnt>)
{
for (int i=;i<=cnt;i++)
{
if (nearcut[i]==)
{
tot++;
ans*=size[i];
}
}
printf("%lld %lld\n",tot,ans);
}
} int main()
{
for(;;)
{
scanf("%d",&n);
if (n==) break;
kase++;
init();
solve();
output();
}
return ;
}

【tarjan求割顶】BZOJ2730-[HNOI2012]矿场搭建的更多相关文章

  1. bzoj2730 [HNOI2012]矿场搭建 (UVAlive5135 Mining Your Own Business)

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1147  Solved: 528[Submit][Statu ...

  2. [BZOJ2730][HNOI2012]矿场搭建 点双 割点

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2852  Solved: 1344[Submit][Stat ...

  3. BZOJ2730——[HNOI2012]矿场搭建

    bzoj2730 & world final 2011 H 1.题目大意:就是有一个无向图,让你在里面选择点,使得,无论哪个点没了以后,其他的点都能到达你选择的任何一个点,输出最少 选择几个点 ...

  4. 【双连通分量】Bzoj2730 HNOI2012 矿场搭建

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

  5. BZOJ2730 [HNOI2012]矿场搭建 - Tarjan割点

    Solution 输入中没有出现过的矿场点是不用考虑的, 所以不用考虑只有 一个点 的点双联通分量. 要使某个挖矿点倒塌, 相当于割去这个点, 所以我们求一遍割点和点双联通分量. 之后的点双联通分量构 ...

  6. [BZOJ2730][HNOI2012]矿场搭建(求割点)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2730 分析: 如果坍塌的点不是割点,那没什么影响,主要考虑坍塌的点是割点的情况. 显然 ...

  7. BZOJ2730: [HNOI2012]矿场搭建

    传送门 图的连通性相关的必和割点割边之类的有关. 题目要求对于一个无向图,任意一点被删除后,所有点都和某些指定点是联通的. 这道题比较简单的做法就是求出来所有的块.对于一个块,如果块里有两个及两个以上 ...

  8. [BZOJ2730]:[HNOI2012]矿场搭建(塔尖)

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

  9. Tarjan水题系列(2):HNOI2012 矿场搭建

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

随机推荐

  1. Django请求原理

    总结一下: 1. 进来的请求转入/hello/. 2. Django通过在ROOT_URLCONF配置来决定根URLconf. 3. Django在URLconf中的所有URL模式中,查找第一个匹配/ ...

  2. OWNER:Java配置文件解决方案 使用简介

    这个感觉还是很方便的一个工具.  学习网站是:http://hao.jobbole.com/owner/ 测试步骤: 1.pom <dependency> <groupId>o ...

  3. C++中的各种“神奇”东西

    将光标放到任意的位置 void gotoxy(int x,int y)//位置函数 { COORD pos; pos.X=x; pos.Y=y; SetConsoleCursorPosition(Ge ...

  4. saltstack入门至放弃之salt安装部署

    学习了一段时间的saltstack,是时候记录下了.友提:学习环境是两台centos_7.2_x64机器 系统初始化: 两台机器执行以下脚本即可(友提:两台服务器的主机名配置在/etc/hosts中, ...

  5. 【BZOJ2820】YY的GCD [莫比乌斯反演]

    YY的GCD Time Limit: 10 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 求1<=x<=N, ...

  6. 【FJWC2017】交错和查询 [线段树]

    交错和查询 Time Limit: 10 Sec  Memory Limit: 256 MB Description 无限循环数字串S由长度为n的循环节s构成.设s为12345(n=5),则数字串S为 ...

  7. Ansible 创建用户 Playbook 脚本

    创建用户,设置wheel组sudo不需要密码,然后将用户添加到wheel组,并将用户的公钥传输到节点上: --- - name: Linux Create User and Upload User P ...

  8. Java相关框架

    框架 类型 设计(个人理解) HK2 自动注入框架 Jersey RESTful Jetty HTTP服务 Retrofit HTTP客户端 ActiveMQ 消息组件 主题.队列 Redis K-V ...

  9. UVALIVE 3891 The Teacher's Side of Math

    One of the tasks students routinely carry out in their mathematics classes is to solve a polynomial ...

  10. sql文格式替换

    SELECT COUNT(1)FROM TAB1 TWHERE T.IS_DEL <> 0 将以上SQL格式替换为代码中的格式 sql.AppendLine(" SELECT & ...