zoukankan      html  css  js  c++  java
  • luogu3225 [HNOI2012]矿场搭建

    题目大意

      给出一个有$n(nleq 500)$个节点的无向图,一个满足条件的点集$V$会使得对于图中的每一个节点$u$,满足路径起点为$u$终点$vin V$的路径集合$P_u$中总存在至少两条路径$p_1,p_2$,使得该两条路径除了起点外没有交集(终点也不同)。输出$|V|$的最小值,以及$|V|$最小时$V$的种类数。

    题解

      对于一个点双连通分量中的任意一对点都有两条路径到达对方,所以我们从点双连通分量入手。

      特殊情况:当一个点双连通分量中没有割点时,根据题目要求,这个点双连通分量中需要有两个点属于$V$。

      若把所有点双连通分量缩点形成一棵树,那么树必定会有叶子节点。所以我们考虑当一个点双连通分量有一个割点时该怎么办。考虑到去掉的点是割点的情况,每个叶子双联通分量内必需有一个点$t$属于$V$;若去掉的点位于所在连通分量以外的部分,双连通分量内的点都与$t$连通;若去掉的点在双连通分量以内且不属于割点,那么双连通分量内的其它点到割点必然存在一条路径,而割点必然与其它叶子双连通分量相连通,那里有属于$V$的点。因此,所有叶子双连通分量内必须有且只有一个点属于$V$。

      若一个点双连通分量不是叶子,那么无论去掉哪个点,这个点双连通分量总与叶子连通,那里有属于$V$的点,所以这里的点双连通分量没有属于$V$的点。

      关于根节点的特判,将根节点所在的点双连通分量记录下来,在Dfs外面对根节点进行特殊处理即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <stack>
    #include <cassert>
    using namespace std;
    
    const int MAX_NODE = 510;
    
    struct Node
    {
        vector<Node*> Next;
        int DfsN, Low;
        bool IsCut;
    }_nodes[MAX_NODE];
    stack<Node*> St;
    
    struct Block
    {
        int NodeCnt, CutCnt;
    }_blocks[MAX_NODE];
    int BlockCnt;
    int DfsCnt;
    vector<Block*> RootIn;
    
    void DeStack(Node *end, Node *add)
    {
        BlockCnt++;
        Node *temp;
        do {
            temp = St.top();
            St.pop();
            _blocks[BlockCnt].NodeCnt++;
            _blocks[BlockCnt].CutCnt += temp->IsCut;
        } while (temp != end);
        _blocks[BlockCnt].NodeCnt++;
        _blocks[BlockCnt].CutCnt += add->IsCut;
    }
    
    int Dfs(Node *cur)
    {
        cur->Low = cur->DfsN = ++DfsCnt;
        St.push(cur);
        int cnt = 0;
        for (int i = 0; i < cur->Next.size(); i++)
        {
            if (!cur->Next[i]->DfsN)
            {
                Dfs(cur->Next[i]);
                cur->Low = min(cur->Low, cur->Next[i]->Low);
                if (cur->Next[i]->Low >= cur->DfsN)
                {
                    cnt++;
                    if (cur != _nodes + 1)
                        cur->IsCut = true;
                    DeStack(cur->Next[i], cur);
                    if (cur == _nodes + 1)
                        RootIn.push_back(_blocks + BlockCnt);
                }
            }
            else
                cur->Low = min(cur->Low, cur->Next[i]->DfsN);
        }
        return cnt;
    }
    
    void Clear()
    {
        for (int i = 1; i < MAX_NODE; i++)
        {
            _nodes[i].Low = _nodes[i].DfsN = _nodes[i].IsCut = 0;
            _nodes[i].Next.clear();
            _blocks[i].CutCnt = _blocks[i].NodeCnt = 0;
        }
        RootIn.clear();
        BlockCnt = 0;
        DfsCnt = 0;
    }
    
    int main()
    {
        int totEdge, caseCnt = 0;
        while (scanf("%d", &totEdge) && totEdge)
        {
            Clear();
            for (int i = 1; i <= totEdge; i++)
            {
                int u, v;
                scanf("%d%d", &u, &v);
                _nodes[u].Next.push_back(_nodes + v);
                _nodes[v].Next.push_back(_nodes + u);
            }
            int rootBlockCnt = Dfs(_nodes + 1);
            if (rootBlockCnt > 1)
            {
                _nodes[1].IsCut = true;
                for (int i = 0; i < RootIn.size(); i++)
                    RootIn[i]->CutCnt++;
            }
            while (!St.empty())
                St.pop();
            int exitCnt = 0;
            long long solCnt = 1;
            for (int i = 1; i <= BlockCnt; i++)
            {
                if (_blocks[i].CutCnt == 0)
                {
                    assert(BlockCnt == 1);
                    exitCnt = 2;
                    solCnt = (long long)_blocks[i].NodeCnt * (_blocks[i].NodeCnt - 1) / 2;
                }
                else if (_blocks[i].CutCnt == 1)
                {
                    exitCnt++;
                    solCnt *= (_blocks[i].NodeCnt - _blocks[i].CutCnt);
                }
            }
            printf("Case %d: %d %lld
    ", ++caseCnt, exitCnt, solCnt);
        }
        return 0;
    }
    

      

  • 相关阅读:
    JDBC
    JDBC连接MYSQL
    Servlet学习(1)
    Apache http server和tomcat的区别
    log4j(转)
    《打造Facebook》
    深入浅出Java三大框架SSH与MVC的设计模式
    Python 爬虫监控女神的QQ空间新的说说,实现秒赞,并发送说说内容到你的邮箱
    Python 爬虫监控女神的QQ空间新的说说,实现邮箱发送
    linux 进程消耗查看
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9482525.html
Copyright © 2011-2022 走看看