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

题目分析:在一张无向图中,将一些点涂上黑色,使得删掉图中任何一个点时,每个连通分量至少有一个黑点。问最少能涂几个黑点,并且在涂最少的情况下有几种方案。

题目分析:显然,一定不能涂割点。对于每一个连通分量,如果有1个割点,则必须涂上分量内除割点之外的任意一个点,如果有多个(2个及以上)割点,则这个分量不需要涂色。如果整张图都没有割点,那么任选两个点涂色即可,之所以要涂两个,是要防止删掉的电恰是黑点的情况。

代码如下:

# include<iostream>
# include<cstdio>
# include<stack>
# include<map>
# include<vector>
# include<cstring>
# include<algorithm>
using namespace std;

const int maxn=100005;
struct Edge
{
    int u,v,nxt;
    Edge(int _u=0,int _v=0,int _nxt=0):u(_u),v(_v),nxt(_nxt){}
};
Edge e[maxn];
int head[maxn],pre[maxn],iscut[maxn],low[maxn],bccno[maxn],cnt,bcc_cnt,dfs_cnt;
map<int,int>mp;
stack<Edge>s;
vector<int>bcc[maxn];

void add(int u,int v)
{
    e[cnt].v=v;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}

void read(int m,int &n)
{
    mp.clear();
    int a,b;
    cnt=n=0;
    memset(head,-1,sizeof(head));
    while(m--)
    {
        scanf("%d%d",&a,&b);
        if(mp[a]==0)
            mp[a]=++n;
        if(mp[b]==0)
            mp[b]=++n;
        add(mp[a]-1,mp[b]-1);
        add(mp[b]-1,mp[a]-1);
    }
}

void dfs(int u,int fa)
{
    int child=0;
    low[u]=pre[u]=++dfs_cnt;
    for(int i=head[u];i!=-1;i=e[i].nxt){
        int v=e[i].v;
        if(!pre[v]){
            ++child;
            s.push(Edge(u,v));
            dfs(v,u);
            low[u]=min(low[v],low[u]);
            if(low[v]>=pre[u]){
                iscut[u]=1;
                bcc[++bcc_cnt].clear();
                while(1)
                {
                    Edge x=s.top();
                    s.pop();
                    if(bccno[x.u]!=bcc_cnt){
                        bcc[bcc_cnt].push_back(x.u);
                        bccno[x.u]=bcc_cnt;
                    }
                    if(bccno[x.v]!=bcc_cnt){
                        bcc[bcc_cnt].push_back(x.v);
                        bccno[x.v]=bcc_cnt;
                    }
                    if(x.u==u&&x.v==v)
                        break;
                }
            }
        }else if(pre[v]<pre[u]&&v!=fa){
            s.push(Edge(u,v));
            low[u]=min(low[u],pre[v]);
        }
    }
    if(fa<0&&child==1)
        iscut[u]=0;
}

void findBcc(int n)
{
    bcc_cnt=dfs_cnt=0;
    memset(pre,0,sizeof(pre));
    memset(low,0,sizeof(low));
    memset(iscut,0,sizeof(iscut));
    memset(bccno,0,sizeof(bccno));
    for(int i=0;i<n;++i)
        if(!pre[i])
            dfs(i,-1);
}

void solve(int k)
{
    long long ans1=0,ans2=1;
    for(int i=1;i<=bcc_cnt;++i){
        int ccnt=0;
        for(int j=0;j<bcc[i].size();++j)
            if(iscut[bcc[i][j]])
                ++ccnt;
        if(ccnt==1)
            ++ans1,ans2*=(long long)(bcc[i].size()-ccnt);
    }
    if(bcc_cnt==1)
        ans1=2,ans2=bcc[1].size()*(bcc[1].size()-1)/2;
    printf("Case %d: %lld %lld\n",k,ans1,ans2);
}

int main()
{
    int n,m,cas=0;
    while(scanf("%d",&m)&&m)
    {
        read(m,n);
        findBcc(n);
        solve(++cas);
    }
    return 0;
}

  

时间: 2024-10-09 11:07:18

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

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

题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 思路:其实本题就相当于在一张无向图中,涂尽量少的黑点,使得任意删除哪个点,每个连通分量至少有一个黑点.因为不同的连通分量最多只有一个公共点,那一定是割点.可以发现,涂黑割点是不划算的,而且在 一个点-双连通分量中涂黑两个黑点也是不划算的.所以只有当点-双连通分量只有一个割点时

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

UVALive - 5135 Mining Your Own Business(双连通分量)

题目大意:有N个矿井 ,由一些隧道连接起来,现在要修建尽量少的安全通道,使得无论哪里发生事故,所有人均能逃出,求建的最少的安全通道数量和方案数 解题思路:建安全通道的话,肯定不能建在割顶,因为割顶如果崩塌了,割顶所连接的双连通分量内的点就跑不掉了,还得在双连通分量里面再建点(上述为双连通分量内部只有一个割顶的情况),这样不划算,还不如直接在里面建点 如果一个双连通分量的内部割顶有多个的话,那么在这个双连通分量里面就可以不用建安全通道了,因为一个割顶崩塌了,还有其他点可以连向外面,所以,只考虑内部

UVALive 5135 Mining Your Own Business

题意: 一些隧道组成矿井  现在要修建尽量少的逃生通道  使得无论哪里发生事故  所有人均能逃出  求方案数 思路: 这道题比较容易联想到割点  因为只有这种点出事矿井才会不连通  那么首先就找出所有割点 分析最少要建几个逃生通道  那当然是每个连通块各一个  因此需要把求出连通块顶点数之积 最后考虑特殊情况  没有割点  那么随便两个地方建就好了  不能建一个  万一就那里出事了呢- 代码: #include<cstdio> #include<cstring> #include&

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 lo

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

时间戳 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算法中将桥存起来!然后

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

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

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

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

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> #