首页 > 其他 > 详细

Mining Your Own Business

时间:2014-03-28 16:55:26      阅读:522      评论:0      收藏:0      [点我收藏+]

题目链接

  • 题意:
    给定一个无向连通图,选择一些特殊点,当图中任意一个点(也有可能是特殊点)被删去的时候,其他点至少能到达一个特殊点
    输入:n表示边数;每行两个数表示一条边(从1开始)
    输出:需要的最少的特殊点和总的方案数
  • 分析:
    首先,如果没有删去点,所有的点都可以到达任意一个特殊点(连通)。主要是分析连通性,所以从割点入手(不要忘了可以删特殊点)
    显然,特殊点如果选割点的话是不划算的。
    对于每一个割点个数为1的图,如果图中没有特殊点,那么至少删去割点,这个图就不能到达特殊点,所以这样的图必须有一个特殊点
    之后,对于任意一个图,如果删除图中的点,那么不影响(不影响连通性);如果删除这个图的一个割点,那么总有一个割点为1的图与之连通

    (个人理解)将所有的点双连通分量缩成一个点,割点变成连接两个点双连通分量的边,那么生成的图是无向无环的图(树)
    那么,删去的点认为就是一个双连通分量(即生成的图中的一个点),删去的边认为是删去了一个割点
    问题就变成了在树中删去一个点或者边,使得所有的点都能到达特殊点,也就是所有的根和叶子为特殊点
  • 特殊情况:当只有一个连通分量时候需要单独考虑,即两个特殊点
  • 重点:
    选取特殊点的位置不能是割点
    特殊点必选在割点数量为1的图中
    考虑到没有割点的图的情况
//无向图的双连通分量
//每次调用前手动清空vector<int> G
//使用时只更新G完成构图
//bcc_cnt从1开始计数

//pre[]表示点在DFS树中的先序时间戳
//iscut[]表示点是否为割点
//bccno[]表示点所在的双连通分量编号
//bcc_cnt表示双连通分量个数
//vector<int> G保存每个点相邻的下一个点序号
//vector<int> bcc保存每个双连通分量的点集,算法运行过程动态清空
//stack<Edge> S是算法用到的栈
const int MAXV = 51000;
const int MAXE = 51000;

int pre[MAXV], iscut[MAXV], bccno[MAXV], dfs_clock, bcc_cnt; // 割顶的bccno无意义
struct Edge
{
    int u, v;
};
vector<int> G[MAXV], bcc[MAXV];
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])   // 没有访问过v
        {
            S.push(e);
            child++;
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv); // 用后代的low函数更新自己
            if(lowv >= pre[u])
            {
                iscut[u] = true;
                bcc_cnt++;
                bcc[bcc_cnt].clear();
                for(;;)
                {
                    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(e);
            lowu = min(lowu, pre[v]); // 用反向边更新自己
        }
    }
    if(fa < 0 && child == 1) iscut[u] = 0;
    return lowu;
}

void find_bcc(int n)
{
    // 调用结束后S保证为空,所以不用清空
    memset(pre, 0, sizeof(pre));
    memset(iscut, 0, sizeof(iscut));
    memset(bccno, 0, sizeof(bccno));
    dfs_clock = bcc_cnt = 0;
    for(int i = 0; i < n; i++)
        if(!pre[i]) dfs(i, -1);
};

int main()
{
//    freopen("in.txt", "r", stdin);
    int n, a, b, kase = 1;
    while (~RI(n) && n)
    {
        REP(i, MAXV) G[i].clear();

        int Max = 0;
        REP(i, n)
        {
            RII(a, b); a--; b--;
            Max = max(Max, max(a, b));
            G[a].push_back(b);
            G[b].push_back(a);
        }
        find_bcc(Max);
        LL ans = 1, cnt = 0;
        if (bcc_cnt == 1)
        {
            LL m = bcc[1].size();
            ans = m * (m - 1) / 2;
            cnt = 2;
        }
        else
        {
            FE(i, 1, bcc_cnt)
            {
                int tcnt = 0;
                REP(j, bcc[i].size())
                {
                    if (iscut[bcc[i][j]])
                        tcnt++;
                }
                if (tcnt == 1)
                {
                    ans *= (bcc[i].size() - 1);
                    cnt++;
                }
            }
        }
        printf("Case %d: ", kase++);
        cout << cnt << ‘ ‘ << ans << endl;
    }
    return 0;
}


Mining Your Own Business,布布扣,bubuko.com

Mining Your Own Business

原文:http://blog.csdn.net/wty__/article/details/22385565

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!