首页 > 其他分享 >P3225 [HNOI2012]矿场搭建 tarjan

P3225 [HNOI2012]矿场搭建 tarjan

时间:2023-01-10 22:46:51浏览次数:53  
标签:tarjan int stk 叶子 HNOI2012 dfn low P3225 节点

// 题意:在一幅无向图图上,删除一个点后,其他所有点上的人还能通过其他点出去,问最少设置几个出口,以及方案数
// 思路:无向图就联想到双联通分量,我们来分类讨论一下
//       1.假设图是一条链,那么我们要保证这个链上至少有两个出口,因为一旦这个链断开,人只能向两侧跑
//       2.假设图是一个双联通图,那么也至少要两个,因为要保证不是出口恰好被ban
//       
//       3.普通情况的话,我们可以想到将原图缩点后,整个图就形成了一棵树了,这个时候就不用考虑双联通分量内部了,那么这种情况下要满足要求,就只能是
//         任意一条树链两端都能到出口。 
//         有之前那道树链覆盖的题的经验,我们可以考虑极端之下,我们把树链尽量延长,那么树链的两头就变成了两个叶子节点
//         于是乎我们发现只要在两头的叶子节点设计出口即可。
//         设想我们如果不是在叶子节点设立,而是在叶子节点上一个节点设立,叶子结点就不满足可以两头跑的特性,我们就要多设立出口在叶子节点
//         所以我们的策略是最优解
//         
//         另外无向图中的叶子结点可以看做是只有一个割点的节点
//
#include<bits/stdc++.h>
using namespace std;
const int N = 1000 + 7;
int m, cnt, ct, ans1;
long long ans2;
vector<int> e[N];
int dfn[N], low[N], idx, cut[N], id;
stack<int> stk;
vector<int> mp[N];
void dfs(int u, int f) {
    dfn[u] = low[u] = ++idx;
    int ch = 0;
    stk.push(u);
    for (auto v : e[u]) {
        if (!dfn[v]) {
            dfs(v, u);
            ch++;
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u]) {
                id++;
                int temp = 0;
                while (1) {
                    temp = stk.top();
                    mp[id].push_back(temp);//因为一个割点可能属于多个双联通分量,所以我们每个都放这个割点,做完后再统计每个分量有多少个割点
                    if (temp == u) break;
                    stk.pop();
                }
                if (u != 1 || ch > 1) cut[u] = 1;
            }
        }
        else if (v != f) {
            low[u] = min(low[u], dfn[v]);
        }
    }
}
void init() {
    stk = stack<int>();
    cnt = 0;
    memset(cut, 0, sizeof(cut));
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    for (int i = 1; i <= id; i++) mp[i].clear();
    idx = id = 0;
    for (int i = 1; i <= N - 1; i++) e[i].clear();
    ans1 = 0, ans2 = 1;
}
int main() {
    while (cin >> m, ++ct) {
        if (m == 0) break;
        init();
        int a, b;
        for (int i = 1; i <= m; i++) {
            cin >> a >> b;
            e[a].push_back(b); e[b].push_back(a);
        }
        dfs(1, -1);//应该是连通图
        for (int i = 1; i <= id; i++) {
            int v1 = mp[i].size(), v2 = 0;
            for (auto x : mp[i]) if (cut[x]) v2++;
            if (v2 == 1) ans1++, ans2 *= v1 - 1;
            if (v2 == 0) ans1 += 2, ans2 *= v1 * (v1 - 1) / 2;
        }
        printf("Case %d: %d %lld\n", ct, ans1, ans2);
    }
    return 0;
}

 

标签:tarjan,int,stk,叶子,HNOI2012,dfn,low,P3225,节点
From: https://www.cnblogs.com/Aacaod/p/17041571.html

相关文章

  • Tarjan好题
    LuoguP5676[GZOI2017]小z玩游戏难度:提高+/省选-标签:Tarjan建图\(\mathtt{blog}\)......
  • Tarjan算法求割点
    定义如果在一个图中,删除某个节点连同与之关联的边,会导致整个图的连通分支数增加,那么这个节点叫做割点(ArticulationPoint,CutVertex)如下图:整个图的连通分支数为1,但......
  • 洛谷P3224 [HNOI2012]永无乡 题解 splay tree 启发式合并
    题目链接:https://www.luogu.com.cn/problem/P3224主要知识点是:树上启发式合并,即每次合并将小的树里面的每个点合并大大的树里面,时间复杂度\(O(n\log^2n)\)。同时需要......
  • hdu2586 How far away ?--tarjan & LCA
    原题链接:​​http://acm.hdu.edu.cn/showproblem.php?pid=2586​​题意:n个点,编号1-n,接下来n-1行,每行三个数字表示两点之间的距离,题目是保证两点间不会出现两条可行的路,也就......
  • tarjan算法
    \(tarjan\)RobertTarjan,计算机科学家,以LCA、强连通分量等算法闻名,同时他还参与了开发斐波那契堆、伸展树的工作。\(Tarjan\)算法是基于深度优先搜索的算法,用于求解图的......
  • 【模板】Tarjan
    postedon2022-07-0720:52:49|under模板|source0x00有向图缩点现有一有向图\(G=(V,E)\),称一个点集\(E'\inE\)为强连通分量,当且仅当\(E'\)的任意两点可以互......
  • Tarjan算法求强连通分量
    \(Tarjan\)——强连通分量首先了解几个概念:强连通,强连通图,强连通分量强连通:在一个有向图\(G\)中,两个点\(a,b\),\(a\)可以走到\(b\),\(b\)可以走到\(a\),我们就说\((a,b)\)......
  • LCA 之 Tarjan(离线)算法
    \(LCA\)之\(Tarjan\)(离线)算法什么是最近公共祖先?在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先......
  • Tarjan算法
    tarjan求无向图割点,若x是根节点,则子树个数>1时x时割点;若x是非根节点,当ipt[x]<=low[y]时x是割点,说明y的子树无法通过非父子边回溯到x的祖先,那么删掉x,图将分裂成两个字图,即x......
  • P3226 [HNOI2012]集合选数(状压 DP)
    P3226[HNOI2012]集合选数要求选出集合\(S\)满足如果\(x\)选择了,\(2x\)和\(3x\)都不能选择。求\(\{1,2,\dots,n\}\)的符合要求的子集数量。\(n\le10^5\)。......