[HNOI2012]矿场搭建【割点Tarjan】

题目链接

  有M条边,告诉你u、v两点有一条无向边,然后点是所有输入点的最大值,现在问如果有任意一个点被删除了,要保证剩下的点都有办法走到出口,所需要的最少建设的出口通道是几个?并且输出方案数。

  很明显一点,如果某个强连通子图没有割点的话,那么说明这个子图==该联通子图,那么只需要从其中所有的点随便选两个点作为出口点即可,方案数为C(N, 2),需要加的点是2个。

  如果,存在一个强连通子图,它有且只有一个割点,那么需要从它内的V-1个点中(排除那个割点)选一个点作为出口点,如果割的不是割点,那么其余点就可以通过走割点方向走出去,如果是割点的话,那个其余点就走这个点走出去。

  如果存在一个强连通子图,它有多个割点(≥2),那么他就不需要再新建点了,它可以从没有被删除的割点方向找到出路。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <string>
  5 #include <cstring>
  6 #include <algorithm>
  7 #include <limits>
  8 #include <vector>
  9 #include <stack>
 10 #include <queue>
 11 #include <set>
 12 #include <map>
 13 #include <bitset>
 14 #include <unordered_map>
 15 #include <unordered_set>
 16 #define lowbit(x) ( x&(-x) )
 17 #define pi 3.141592653589793
 18 #define e 2.718281828459045
 19 #define INF 0x3f3f3f3f
 20 #define HalF (l + r)>>1
 21 #define lsn rt<<1
 22 #define rsn rt<<1|1
 23 #define Lson lsn, l, mid
 24 #define Rson rsn, mid+1, r
 25 #define QL Lson, ql, qr
 26 #define QR Rson, ql, qr
 27 #define myself rt, l, r
 28 #define pii pair<int, int>
 29 #define MP(a, b) make_pair(a, b)
 30 using namespace std;
 31 typedef unsigned long long ull;
 32 typedef unsigned int uit;
 33 typedef long long ll;
 34 const int maxN = 1e3 + 7;
 35 int N, M, head[maxN], cnt;
 36 struct Eddge
 37 {
 38     int nex, to;
 39     Eddge(int a=-1, int b=0):nex(a), to(b) {}
 40 }edge[maxN << 1];
 41 bool vis[maxN << 1] = {false};
 42 void addEddge(int u, int v)
 43 {
 44     edge[cnt] = Eddge(head[u], v); vis[cnt] = false;
 45     head[u] = cnt++;
 46 }
 47 inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
 48 int dfn[maxN], low[maxN], tot = 0, Stap[maxN], Stop, Bcnt, Bhave_cut[maxN] = {0};
 49 bool iscut[maxN] = {false};
 50 vector<int> Bt[maxN], V;
 51 void Tarjan(int u, int fa)
 52 {
 53     int child = 0;
 54     V.push_back(u);
 55     dfn[u] = low[u] = ++tot;
 56     Stap[++Stop] = u;
 57     for(int i=head[u], v; ~i; i=edge[i].nex)
 58     {
 59         if(vis[i]) continue;
 60         vis[i] = vis[i ^ 1] = true;
 61         v = edge[i].to;
 62         if(!dfn[v])
 63         {
 64             child++;
 65             Tarjan(v, u);
 66             low[u] = min(low[u], low[v]);
 67             if(low[v] >= dfn[u])
 68             {
 69                 iscut[u] = true;
 70                 int p; Bcnt++; Bt[Bcnt].clear(); Bhave_cut[Bcnt] = 0;
 71                 do
 72                 {
 73                     p = Stap[Stop--];
 74                     Bt[Bcnt].push_back(p);
 75                 } while(p ^ v);
 76                 Bt[Bcnt].push_back(u);
 77             }
 78         }
 79         else low[u] = min(low[u], dfn[v]);
 80     }
 81     if(!fa && child == 1) iscut[u] = false;
 82 }
 83 inline void init()
 84 {
 85     cnt = tot = Bcnt = Stop = 0;
 86     memset(dfn, 0, sizeof(dfn));
 87     memset(iscut, false, sizeof(iscut));
 88     memset(head, -1, sizeof(head));
 89 }
 90 int main()
 91 {
 92     int Cas = 0;
 93     while(scanf("%d", &M) && M)
 94     {
 95         init(); N = 0;
 96         for(int i=1, u, v; i<=M; i++)
 97         {
 98             scanf("%d%d", &u, &v); N = max(N, max(u, v));
 99             _add(u, v);
100         }
101         ull ans_num = 0, ans_sum = 1;
102         for(int i=1, len, cnum; i<=N; i++)
103         {
104             if(!dfn[i])
105             {
106                 V.clear();
107                 Bcnt = 0;
108                 Tarjan(i, 0);
109                 len = (int)V.size();
110                 cnum = 0;
111                 for(int j=0; j<len; j++)
112                 {
113                     if(iscut[V[j]]) cnum++;
114                 }
115                 if(!cnum)
116                 {
117                     ans_num += 2;
118                     ans_sum *= 1LL * len * (len - 1) / 2;
119                 }
120                 else
121                 {
122                     for(int j=1; j<=Bcnt; j++)
123                     {
124                         for(int v : Bt[j]) if(iscut[v]) Bhave_cut[j]++;
125                         if(Bhave_cut[j] == 1)
126                         {
127                             ans_num++;
128                             ans_sum *= (Bt[j].size() - 1);
129                         }
130                     }
131                 }
132             }
133         }
134         printf("Case %d: %llu %llu
", ++Cas, ans_num, ans_sum);
135     }
136     return 0;
137 }
原文地址:https://www.cnblogs.com/WuliWuliiii/p/13814799.html