hdu3844 Mining Your Own Business,无向图的双连通分量

点击打开链接

无向图的双连通分量

#include<cstdio>
#include<stack>
#include<vector>
#include<map>
#include<algorithm>
#include<cstring>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;
typedef long long LL;
const int maxn = 50010;
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;
vector<int> g[maxn], bcc[maxn];
stack<Edge> S;
int dfs(int u, int fa)
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    for(int i = 0; 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] = 1;
                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].push_back(x.u);
                    }
                    if(bccno[x.v] != bcc_cnt) {
                        bccno[x.v] = bcc_cnt;
                        bcc[bcc_cnt].push_back(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 == 1 && fa < 0) iscut[u] = 0;
    return low[u] = lowu;
}
void find_bcc(int n)
{
    memset(iscut, 0, sizeof(iscut));
    memset(pre, 0, sizeof(pre));
    memset(bccno, 0, sizeof(bccno));

    dfs_clock = bcc_cnt = 0;
    for(int i = 0; i < n; i++)
        if(!pre[i]) dfs(i, -1);
}
int kase;
void solve(int n)
{
    find_bcc(n);
    LL ans1 = 0, ans2 = 1;
    for(int i = 1; i <= bcc_cnt; i++) {
        int cut_cnt = 0;
        for(int j = 0; j < bcc[i].size(); j++)
            if(iscut[bcc[i][j]]) cut_cnt++;
        if(cut_cnt == 1)
            ans1++, ans2 *= (LL)(bcc[i].size() - cut_cnt);
    }
    if(bcc_cnt == 1) {
        ans1 = 2, ans2 = (LL)(n-1)*n/2;
    }
    printf("Case %d: %I64d %I64d\n", kase, ans1, ans2);
}
int main(void)
{
    int m;
    while(scanf("%d", &m), m) {
        kase++;
        for(int i = 0; i < maxn; i++)
            g[i].clear();
        int mxn = 0;
        while(m--) {
            int u, v;
            scanf("%d%d", &u, &v);
            mxn = max(mxn, max(u, v));
            u--, v--;
            g[u].push_back(v), g[v].push_back(u);
        }
        solve(mxn);
    }
    return 0;
}
时间: 2024-10-24 13:59:23

hdu3844 Mining Your Own Business,无向图的双连通分量的相关文章

hdu 3844 Mining Your Own Business (点双连通分量)

Mining Your Own Business Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1392    Accepted Submission(s): 219 Problem Description John Digger is the owner of a large illudium phosdex mine. The m

连通分量 无向图的割顶和桥 无向图的双连通分量 有向图的强连通分量

时间戳 dfs_clock :说白了就是记录下访问每个结点的次序.假设我们用 pre 保存,那么如果 pre[u] > pre[v], 那么就可以知道先访问的 v ,后访问的 u . 现在给定一条边, (u, v), 且 u 的祖先为 fa, 如果有 pre[v] < pre[u] && v != fa, 那么 (u, v) 为一条反向边. 1 求连通分量: 相互可达的节点称为一个连通分量: #include <iostream> #include <cstd

hdu Caocao&#39;s Bridges(无向图边双连通分量,找出权值最小的桥)

1 /* 2 题意:给出一个无向图,去掉一条权值最小边,使这个无向图不再连同! 3 4 tm太坑了... 5 1,如果这个无向图开始就是一个非连通图,直接输出0 6 2,重边(两个节点存在多条边, 权值不一样) 7 3,如果找到了桥的最小权值为0,也就是桥上的士兵数为0,那么还是要最少派一个 8 士兵过去炸掉桥! 9 10 思路:假设每两个节点最多只有一条边进行相连! 11 进行tarjan算法,如果该算法调用了超过2次,说明这个原图就是不连通的! 12 否则在tarjan算法中将桥存起来!然后

图论--无向图点双连通分量模板

对于一个无向图,如果一个点集,它内部的任意一个点对之间,至少有两条点完全不重复的路径,那么这个点集就是原图的一个点双连通分量,而点双联通分量之间是由割点隔开,割点就是如果删去这个点,原图的连通块数会增加,那么这个点就是割点. 通过tarjan算法,我们可以用一次 dfs 标记出所有的割点以及所有双连通分量. 注释版: 1 #include<stdio.h> 2 #include<string.h> 3 #include<stack> 4 #include<algo

UVALive - 3523 Knights of the Round Table(无向图的双连通分量)

题目大意:有n个骑士经常举行圆桌会议,每次圆桌会议至少要有3个骑士参加(且每次参加的骑士数量是奇数个),且所有互相憎恨的骑士不能坐在圆桌旁的相邻位置,问有多少个骑士不可能参加任何一个会议 解题思路:以骑士为点建立无向图G.如果两个骑士可以相邻(即他们并不互相憎恨),即可连一条边. 则题目就转化为求不在任何一个简单奇圈上的结点个数 首先,圈就是一个双连通的分量,所以第一件事就是将所有的双连通分量求出来,接着再判定这个双连通分量是不是奇圈 奇圈的判定就是用二分图染色判定,如果某个圈能被二分图染色,那

poj 2942 Knights of the Round Table(无向图的双连通分量+二分图判定)

#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #

无向图的割顶和桥,无向图的双连通分量入门详解及模板 -----「转载」

https://blog.csdn.net/stillxjy/article/details/70176689 割顶和桥:对于无向图G,如果删除某个节点u后,连通分量数目增加,则称u为图的割顶:如果删除某条边后,连通分量数目增加,则称该边为图的桥.对于连通图删除割顶或桥后都会使得图不再连通 以下我,我们利用dfs的性质来快速找出一个连通图中的所有的割顶和桥 首先我们要引入”时间戳”这个概念: 时间戳:表示在进行dfs时,每个节点被访问的先后顺序.每个节点会被标记两次,分别用pre[],和post

UVA5135 Mining Your Own Business ( 无向图双连通分量)

题目链接 题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 分析:本题相当于在一张无向图上选择尽量少的点涂黑(对应太平井),使任意一个点被删除后,每个连通分量都至少还有一个黑点.不同的连通分量最多有一个公共点即割点,将割点涂上是不划算的,因为删除割点后,要保证每个连通分量还要有黑点,所以还要在其他的连通分量中涂黑点,如果不涂

UVALive-5135 Mining Your Own Business (无向图的双连通分量)

题目分析:在一张无向图中,将一些点涂上黑色,使得删掉图中任何一个点时,每个连通分量至少有一个黑点.问最少能涂几个黑点,并且在涂最少的情况下有几种方案. 题目分析:显然,一定不能涂割点.对于每一个连通分量,如果有1个割点,则必须涂上分量内除割点之外的任意一个点,如果有多个(2个及以上)割点,则这个分量不需要涂色.如果整张图都没有割点,那么任选两个点涂色即可,之所以要涂两个,是要防止删掉的电恰是黑点的情况. 代码如下: # include<iostream> # include<cstdio