刘汝佳白书上面的一道题目:题意是给定一个联通分量,求出割顶以及双连通分量的个数,并且要求出安放安全井的种类数,也就是每个双连通分量中结点数(除开 割顶)个数相乘,对于有2个及以上割顶的双连通分量可以不用安放安全井。如果整个图就是一个双连通分量,那么需要安放两个安全井,种类数是n*(n-1)/2.

代码来自刘汝佳白书:

 #include <iostream>
#include <sstream>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define esp 1e-6
#define pi acos(-1.0)
#define pb push_back
#define mp(a, b) make_pair((a), (b))
#define in freopen("in.txt", "r", stdin);
#define out freopen("out.txt", "w", stdout);
#define print(a) printf("%d\n",(a));
#define bug puts("********))))))");
#define stop system("pause");
#define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++)
#define pragma comment(linker, "/STACK:102400000, 102400000")
#define inf 0x0f0f0f0f using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int, int> pii;
typedef vector<pii,int> VII;
typedef vector<int>:: iterator IT;
const int maxn = ;
struct Edge{
int u, v;
Edge(int u, int v):u(u), v(v){}
};
int pre[maxn], low[maxn], bccno[maxn], iscut[maxn], bcc_cnt, dfs_clock;
VI g[maxn], bcc[maxn];
stack<Edge> S;
int dfs(int u, int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = ;
for(int i = ; i < g[u].size(); i++)
{
int v = g[u][i]; Edge e = Edge(u, v);
if(!pre[v])
{
S.push(e);
child++;
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if(lowv >= pre[u])
{
iscut[u] = ;
bcc_cnt++; bcc[bcc_cnt].clear();
for(;;)
{
Edge x = S.top(); S.pop();
if(bccno[x.u] != bcc_cnt) {bccno[x.u] = bcc_cnt; bcc[bcc_cnt].pb(x.u);}
if(bccno[x.v] != bcc_cnt) {bccno[x.v] = bcc_cnt; bcc[bcc_cnt].pb(x.v);}
if(x.u == u && x.v == v) break;
}
}
}
else if(pre[v] < pre[u] && v!= fa)
{
S.push(e);
lowu = min(lowu, pre[v]);
}
}
if(child == && fa < ) iscut[u] = ;
return low[u] = lowu;
}
void find_bcc(int n)
{
memset(iscut, , sizeof(iscut));
memset(pre, , sizeof(pre));
memset(bccno, , sizeof(bccno)); dfs_clock = bcc_cnt = ;
for(int i = ; i < n; i++)
if(!pre[i]) dfs(i, -);
}
int kase;
void solve(int n)
{
find_bcc(n);
LL ans1 = , ans2 = ;
for(int i = ; i <= bcc_cnt; i++)
{
int cut_cnt = ;
for(int j = ; j < bcc[i].size(); j++)
if(iscut[bcc[i][j]]) cut_cnt++;
if(cut_cnt == )
ans1++, ans2 *= (LL)(bcc[i].size() - cut_cnt);
}
if(bcc_cnt == )
{
ans1 = , ans2 = (LL)(n-)*n/;
}
printf("Case %d: %I64d %I64d\n", kase, ans1, ans2);
}
int main(void)
{
int m;
while(scanf("%d", &m), m)
{
kase++;
for(int i = ; i < maxn; i++)
g[i].clear();
int mxn = ;
while(m--)
{
int u, v;
scanf("%d%d", &u, &v);
mxn = max(mxn, max(u, v));
u--, v--;
g[u].pb(v), g[v].pb(u);
}
solve(mxn);
}
return ;
}

此题的另一种解法是先求出割顶,然后从非割顶的点dfs一遍,注意这个过程中不能经过割顶,统计每次dfs中遇到割顶的数目,如果为1,则更新答案。同样注意割顶为0的情况。

代码:

 #include <iostream>
#include <sstream>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <string>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#define esp 1e-6
#define pi acos(-1.0)
#define pb push_back
#define mp(a, b) make_pair((a), (b))
#define in freopen("in.txt", "r", stdin);
#define out freopen("out.txt", "w", stdout);
#define print(a) printf("%d\n",(a));
#define bug puts("********))))))");
#define stop system("pause");
#define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++)
#define inf 0x0f0f0f0f
#pragma comment(linker, "/STACK:102400000,102400000") using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int, int> pii;
typedef vector<pii,int> VII;
typedef vector<int>:: iterator IT;
const int maxn = + ;
int pre[maxn], low[maxn], iscut[maxn], dfs_clock;
VI g[maxn], cut;
int n;
LL ans1, ans2, cut_cnt;
int dfs(int u, int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = ;
for(int i = ; i < g[u].size(); i++)
{
int v = g[u][i];
if(!pre[v])
{
child++;
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if(lowv >= pre[u])
{
iscut[u] = ;
}
}
else if(pre[v] < pre[u] && v != fa)
{
lowu = min(lowu, pre[v]);
}
}
if(child == && fa < )
iscut[u] = ;
return low[u] = lowu;
}
void find_bcc(int n)
{
memset(pre, , sizeof(pre));
memset(iscut, , sizeof(iscut));
dfs_clock = ;
for(int i = ; i < n; i++)
if(!pre[i])
dfs(i, -);
}
int cnt;
void dfs1(int u)
{
cnt++;
pre[u] = ;
for(int i = ; i < g[u].size(); i++)
{
int v = g[u][i];
if(!pre[v])
{
if(iscut[v]) cut_cnt++, cnt++, pre[v] = , cut.pb(v);
else dfs1(v);
}
}
}
void solve(int n)
{
cut.clear();
cut_cnt= ;
memset(pre, , sizeof(pre));
for(int i = ; i < n; i++)
if(iscut[i]) cut_cnt++; if(cut_cnt == ) ans1 = , ans2 = (LL)n*(n-)/;
else for(int i = ; i < n; i++)
if(!pre[i] && !iscut[i])
{
cut_cnt = cnt = ;
dfs1(i);
for(int i = ; i < cut.size(); i++)
pre[cut[i]] = ;
cut.clear();
if(cut_cnt == )
ans1++, ans2 *= (LL)(cnt-);
}
}
int main(void)
{
int m, t = ;
while(scanf("%d", &m), m)
{
n = ;
ans1 = , ans2 = ;
for(int i = ; i < maxn; i++)
g[i].clear();
while(m--)
{
int u, v;
scanf("%d%d", &u, &v);
n = max(n, max(u, v));
u--, v--;
g[u].pb(v);
g[v].pb(u);
}
find_bcc(n);
solve(n);
printf("Case %d: %I64d %I64d\n", t, ans1, ans2);
t++;
}
return ;
}

UVALive - 5135 Mining Your Own Business的更多相关文章

  1. UVALive - 5135 - Mining Your Own Business(双连通分量+思维)

    Problem   UVALive - 5135 - Mining Your Own Business Time Limit: 5000 mSec Problem Description John D ...

  2. UVALive 5135 Mining Your Own Business 双连通分量 2011final

    题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱, ...

  3. UVALive 5135 Mining Your Own Business 双连通分量

    据说这是一道Word Final的题,Orz... 原题链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&a ...

  4. LA 5135 Mining Your Own Business

    求出 bcc 后再……根据大白书上的思路即可. 然后我用的是自定义的 stack 类模板: #include<cstdio> #include<cstring> #includ ...

  5. UVALive 5135 Mining Your Own Bussiness【tarjan点双】

    LINK1 LINK2 题目大意 给你一个无向连通图,让你给一些点染上黑色,需要满足染色之后,断开任意一个节点,要满足任意一个联通块中剩下的节点中至少有一个黑点 思路 一开始想的是把每一个点双联通分量 ...

  6. 【LA】5135 Mining Your Own Business

    [算法]点双连通分量 [题解]详见<算法竞赛入门竞赛入门经典训练指南>P318-319 细节在代码中用important标注. #include<cstdio> #includ ...

  7. 训练指南 UVALive - 5135 (双连通分量)

    layout: post title: 训练指南 UVALive - 5135 (双连通分量) author: "luowentaoaa" catalog: true mathja ...

  8. HDU3844 Mining Your Own Business

    HDU3844 Mining Your Own Business 问题描述John Digger是一个大型illudium phosdex矿的所有者.该矿山由一系列隧道组成,这些隧道在各个大型交叉口相 ...

  9. 「题解报告」SP16185 Mining your own business

    题解 SP16185 Mining your own business 原题传送门 题意 给你一个无向图,求至少安装多少个太平井,才能使不管那个点封闭,其他点都可以与有太平井的点联通. 题解 其他题解 ...

随机推荐

  1. Visual Studio.NET、asp.net和C#间的关系是怎样的?

    asp.net是一种技术,要实现这种技术,就得有底层的实现技术编程语言,这个语言就是C#,(只是绝大多数首选C#),要想用C#实现asp.net技术,就得有编程的工具软件,这个软件我一直用visual ...

  2. Unity3D 之射线检测

    这里来记录下射线检测的相关内容: 射线检测故名就是通过射线去检测是否和碰撞器产生了交集,和碰撞器与碰撞器发生交集一样,会返回一个真. 射线的用法很多:比如检测是否跳跃,通过向地面投射射线控制在地面时候 ...

  3. kettle中Get Data from XML , Jason Input , 文本文件输入 使用示例

    1.Get Data from XML xml文件内容: <head> <img id="1">菜||焦溜丸子||2013-03-28/image/0/00 ...

  4. 如何给windows窗体程序打包成一个安装包

    http://blog.csdn.net/xyy410874116/article/details/6341787 给windows窗体程序打包成一个安装包:具体操作在:http://hi.baidu ...

  5. php Composer中国全量镜像

    http://pkg.phpcomposer.com/ http://www.yiichina.com/doc/guide/2.0/intro-upgrade-from-v1 https://getc ...

  6. 利用openssl进行RSA加密解密

    openssl是一个功能强大的工具包,它集成了众多密码算法及实用工具.我们即可以利用它提供的命令台工具生成密钥.证书来加密解密文件,也可以在利用其提供的API接口在代码中对传输信息进行加密. RSA是 ...

  7. Mysql 的函数

    函数 MySQL函数分为系统函数与自定义函数 系统函数: pow(m,n)        求m的n次方 rand()            随机获取0至1之间的小数 floor();          ...

  8. 12_CXF入门

    [CXF] Apache CXF = Celtix + Xfire,开始叫 Apache CeltiXfire,后来更名为 Apache CXF 了,以下简称为 CXF.Apache CXF 是一个开 ...

  9. VIM 语法检查

    VIM Grammar Check 一.Language Tool Create by Dominique Pellé REFER:LanguageTool wikipedia REFER:Langu ...

  10. C++里的int 和string类型相互转换

    C++不像Java和C#一样在进行数据类型转换时直接调用一些类方法就可以了,使用起来很简单. 一个很简单的例子就是string str=“D:\\”+1+“.txt”;这在Java或者C#里面是可以自 ...