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;
    }
    

      

  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9482525.html
Copyright © 2011-2022 走看看