hdu3844 Mining Your Own Business

本文深入解析了双连通分量与割点的算法实现,通过实例展示了如何在广义圆方树上选取特定节点,避免了实际建树过程,直接找出双连通分量中的非割点,提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

http://acm.hdu.edu.cn/showproblem.php?pid=3844

题解

画一画样例,然后可以感觉到答案肯定就是在在广义圆方树上把所有叶子节点(方点)所代表的那些双连通分量中的非割点给选中
但是不用真的建圆方树,因为我只需要叶子节点,树上度为 1 1 1的就是叶子节点,我只要找出所有双联通分量,找到那些只包含一个割点的双连通分量就好了

代码

#include <bits/stdc++.h>
#define maxn 100010
#define maxe 100010
using namespace std;
struct Graph
{
    int etot, head[maxn], to[maxe], next[maxe], w[maxe];
    void clear(int N)
    {
        for(int i=1;i<=N;i++)head[i]=0;
        etot=0;
    }
    void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
}G;
struct BiconnectedComponent
{
    int dfn[maxn], low[maxn], iscut[maxn], bccno[maxn], tim, tot;
    vector<int> bcc[maxn];
    typedef pair<int,int> pii;
    stack<pii> s;
    void dfs(Graph &G, int pos, int pre)
    {
        int ch=0;
        dfn[pos]=low[pos]=++tim;
        for(auto p=G.head[pos];p;p=G.next[p])
            if(!dfn[G.to[p]])
            {
                ch++;
                s.push(pii(pos,G.to[p]));
                dfs(G,G.to[p],pos);
                low[pos]=min(low[pos],low[G.to[p]]);
                if(low[G.to[p]]>=dfn[pos])
                {
                    iscut[pos]=1;
                    bcc[++tot].clear();
                    while(1)
                    {
                        auto u=s.top().first, v=s.top().second; s.pop();
                        if(bccno[u]!=tot)bcc[tot].push_back(u), bccno[u]=tot;
                        if(bccno[v]!=tot)bcc[tot].push_back(v), bccno[v]=tot;
                        if(u==pos and v==G.to[p])break;
                    }
                }
            }
            else if(dfn[G.to[p]]<dfn[pos] and G.to[p]!=pre)
            {
                s.push(pii(pos,G.to[p]));
                low[pos]=min(low[pos],dfn[G.to[p]]);
            }
            if(pre<0 and ch==1)iscut[pos]=0;
    }
    void run(Graph &G, int N)
    {
        int i;
        for(i=1;i<=N;i++)bccno[i]=iscut[i]=dfn[i]=0;
        tim=tot=0;
        for(i=1;i<=N;i++)if(!dfn[i])dfs(G,i,-1);
    }
}BCC;
int M, mark[maxn];
long long cnt;
int main()
{
    ios::sync_with_stdio(false);
    int i, u ,v, kase=0, ans;
    while(cin>>M, M)
    {
        cout<<"Case "<<++kase<<": ";
        G.clear(100000);
        for(i=1;i<=M;i++)
        {
            cin>>u>>v;
            G.adde(u,v);
            G.adde(v,u);
        }
        BCC.run(G,100000);
        ans=0;
        cnt=1;
        for(i=1;i<=BCC.tot;i++)
        {
            int cut_cnt=0;
            for(auto x:BCC.bcc[i])if(BCC.iscut[x])cut_cnt++;
            if(cut_cnt==1)cnt*=BCC.bcc[i].size()-1, ans++;
        }
        if(BCC.tot==1)
        {
            ans=2;
            long long t=BCC.bcc[1].size();
            cnt=t*(t-1)/2;
        }
        cout<<ans<<' '<<cnt<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值