割点桥双连通分量

Posted 惜取少年时

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了割点桥双连通分量相关的知识,希望对你有一定的参考价值。

HDU3844

引用训练指南上的题意模型“在一个无向图上选择尽量少的点涂黑,使得任意删除一个点后,每个连同分量至少有一个黑点”

对整个图分两种情况讨论:

1、整个连通图无割顶,即只有1个双连通分量。此时只需要任选2点染色即可

2、有若干的双连通分量。易证此时我们只需要在只有1个割顶的双连通分量中染任意非割顶的点。

技术分享
  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <set>
  6 #include <map>
  7 #include <string>
  8 #include <cstring>
  9 #include <stack>
 10 #include <queue>
 11 #include <cmath>
 12 #include <ctime>
 13 #include <bitset>
 14 #include <utility>
 15 #include <assert.h>
 16 using namespace std;
 17 #define rank rankk
 18 #define mp make_pair
 19 #define pb push_back
 20 #define xo(a,b) ((b)&1?(a):0)
 21 #define tm tmp
 22 //#pragma comment(linker, "/STACK:1024000000,1024000000") 
 23 //#define LL ll
 24 typedef unsigned long long ull;
 25 typedef pair<int,int> pii;
 26 typedef long long ll;
 27 typedef pair<ll,int> pli;
 28 typedef pair<ll,ll> pll;
 29 const int INF=0x3f3f3f3f;
 30 const ll INFF=0x3f3f3f3f3f3f3f3fll;
 31 const int MAX=4e5+10;
 32 //const ll MAXN=2e8;
 33 //const int MAX_N=MAX;
 34 const ll MOD=998244353;
 35 //const long double pi=acos(-1.0);
 36 //const double eps=0.00000001;
 37 ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
 38 template<typename T>inline T abs(T a) {return a>0?a:-a;}
 39 template<class T> inline
 40 void read(T& num) {
 41     bool start=false,neg=false;
 42     char c;
 43     num=0;
 44     while((c=getchar())!=EOF) {
 45         if(c==-) start=neg=true;
 46         else if(c>=0 && c<=9) {
 47             start=true;
 48             num=num*10+c-0;
 49         } else if(start) break;
 50     }
 51     if(neg) num=-num;
 52 }
 53 inline ll powMM(ll a,ll b,ll M){
 54     ll ret=1;
 55     a%=M;
 56 //    b%=M;
 57     while (b){
 58         if (b&1) ret=ret*a%M;
 59         b>>=1;
 60         a=a*a%M;
 61     }
 62     return ret;
 63 }
 64 void open()
 65 {
 66 //    freopen("1009.in","r",stdin);
 67     freopen("out.txt","w",stdout);
 68 }
 69 
 70 const int maxn=1e5+5;
 71 struct Edge{int u,v;};
 72 int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;//bccno记录每一点所属的BCC的编号
 73 vector<int> G[maxn],bcc[maxn];//bcc数组存储某一BCC中所有的点  G存原图
 74 stack<Edge>S;
 75 int dfs(int u,int fa)
 76 {
 77     int lowu=pre[u]=++dfs_clock;
 78     int child=0;
 79     for(int i=0;i<G[u].size();i++)
 80     {
 81         int v=G[u][i];
 82         Edge e=(Edge){u,v};
 83         if(!pre[v])//未访问过v
 84         {
 85             S.push(e);child++;
 86             int lowv=dfs(v,u);
 87             lowu=min(lowu,lowv);//用后代的low函数更新自己
 88             if(lowv>=pre[u])
 89             {
 90                 iscut[u]=true;//是割顶
 91                 bcc_cnt++;//双连通分量个数++
 92                 bcc[bcc_cnt].clear();//注意!bcc从1开始编号
 93                 for(;;)
 94                 {
 95                     Edge x=S.top();S.pop();
 96                     if(bccno[x.u]!=bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;}
 97                     if(bccno[x.v]!=bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;}
 98                     if(x.u==u&&x.v==v)break;//到了当前割顶的边
 99                 }
100             }
101         }
102         else if(pre[v]<pre[u]&&v!=fa)
103         {
104             S.push(e);lowu=min(lowu,pre[v]);//用反向边更新自己
105         }
106     }
107     if(fa<0&&child==1)iscut[u]=0;
108     return lowu;
109 }
110 void find_bcc(int n)
111 {
112     //调用结束后S保证为空 所以不用清空
113     memset(pre,0,sizeof(pre));
114     memset(iscut,0,sizeof(iscut));
115     memset(bccno,0,sizeof(bccno));
116     dfs_clock=bcc_cnt=0;
117     for(int i=1;i<=n;i++)//默认图顶点编号0开始 如果需要1开始可以直接更改
118         if(!pre[i])dfs(i,-1);
119 }
120 int n,x,y,da,cut_cnt,Case;
121 ll cnt,ge;
122 int main()
123 {
124     while(scanf("%d",&n)&&n)
125     {
126         ge=da=0;cnt=1;
127         for(int i=1;i<=(n+1);i++)G[i].clear();
128         for(int i=1;i<=n;i++){scanf("%d%d",&x,&y);G[x].pb(y);G[y].pb(x);da=max(da,x);da=max(da,y);}
129         find_bcc(da);
130         for(int i=1;i<=bcc_cnt;i++)
131         {
132             cut_cnt=0;
133             for(int j=0;j<bcc[i].size();j++)
134                 if(iscut[bcc[i][j]])++cut_cnt;
135             if(cut_cnt==1)
136                 ++ge,cnt*=(bcc[i].size()-1);
137         }
138         if(bcc_cnt==1)
139             ge=2,cnt=1LL*da*(da-1LL)/2LL;
140         printf("Case %d: %lld %lld\n",++Case,ge,cnt);
141     }
142     return 0;
143 }
View Code

 

以上是关于割点桥双连通分量的主要内容,如果未能解决你的问题,请参考以下文章

图的割点桥与双连通分支

图的割点桥与双连通分支

图的割点桥和双连通分支的基本概念

双连通分量

「学习笔记」双连通分量割点与桥

双连通分量(点-双连通分量&边-双连通分量)