【LA5135 訓練指南】井下礦工 【雙連通份量】

題意ios

  有一座地下稀有金屬礦由n條隧道和一些鏈接點組成,其中每條隧道鏈接兩個鏈接點。任意兩個鏈接點之間最多隻有一條隧道。爲了下降礦工的危險,你的任務是在一些鏈接點處安裝太平井和相應的逃生裝置,使得無論哪一個鏈接點倒塌,不在此鏈接點的多有礦工都能到達太平井逃生。爲節約成本,你應當在儘可能少的鏈接點安裝太平井。還須要計算出當太平井的數目最小時的安裝方案總數。ide

分析spa

 1對於一個雙連通份量,若是它有兩個以上的割頂,則不須要建太平井。若是隻有一個割頂,則任選一個非割頂的點建太平井。code

 2若整個圖無割頂,則任塗兩個點,方案數爲n*(n-1)/2blog

 3對於不屬於雙連通份量的點,只能在他們每一個點都建一個太平井string

 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <stack>
 6 #include <vector>
 7 
 8 using namespace std;  9 const int maxn=100000+100;  10 int n,sz,N;  11 int head[maxn],Next[maxn],to[maxn];  12 struct Edge{  13     int u,v;  14 };  15 void add_edge(int a,int b){  16     ++sz;  17     to[sz]=b;Next[sz]=head[a];head[a]=sz;  18 }  19 int ansn;  20 long long anss;  21 int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;  22 vector<int>bcc[maxn];  23 stack<Edge>S;  24 int dfs(int u,int fa){  25     int lowu=pre[u]=++dfs_clock;  26     int child=0;  27     for(int i=head[u];i!=-1;i=Next[i]){  28         int v=to[i];  29         Edge e=(Edge){u,v};  30         if(!pre[v]){  31  S.push(e);  32             child++;  33             int lowv=dfs(v,u);  34             lowu=min(lowu,lowv);  35             if(lowv>=pre[u]){  36                 iscut[u]=1;  37                 bcc_cnt++;bcc[bcc_cnt].clear();  38                 for(;;){  39                     Edge x=S.top();S.pop();  40                     if(bccno[x.u]!=bcc_cnt){  41  bcc[bcc_cnt].push_back(x.u);  42                         bccno[x.u]=bcc_cnt;  43  }  44                     if(bccno[x.v]!=bcc_cnt){  45  bcc[bcc_cnt].push_back(x.v);  46                         bccno[x.v]=bcc_cnt;  47  }  48                     if(x.u==u&&x.v==v)break;  49  }  50  }  51  }  52         else if(pre[v]<pre[u]&&v!=fa){  53  S.push(e);  54             lowu=min(lowu,pre[v]);  55  }  56  }  57     if(fa<0&&child==1)iscut[u]=0;  58     return lowu;  59 }  60 void find_bcc(int n){  61     memset(pre,0,sizeof(pre));  62     memset(iscut,0,sizeof(iscut));  63     memset(bccno,0,sizeof(bccno));  64     dfs_clock=bcc_cnt=0;  65     for(int i=1;i<=n;i++)  66         if(!pre[i])dfs(i,-1);  67 }  68 int kase;  69 int main(){  70     kase=0;  71     while(scanf("%d",&n)!=EOF&&n){  72         int a,b;  73         sz=0;  74         memset(head,-1,sizeof(head));  75         N=0;  76         ansn=0;  77         anss=1;  78         for(int i=1;i<=n;i++){  79             scanf("%d%d",&a,&b);  80             N=max(N,a);  81             N=max(N,b);  82  add_edge(a,b);  83  add_edge(b,a);  84  }  85  find_bcc(N);  86         for(int i=1;i<=bcc_cnt;i++){  87             int num=0;  88             for(int j=0;j<bcc[i].size();j++){  89                 if(iscut[bcc[i][j]])  90                     num++;  91  }  92             if(num==1){  93                 ansn++;  94                 anss*=(long long)(bcc[i].size()-1);  95  }  96             if(num==0){  97                 ansn+=2;  98                 anss*=(long long)bcc[i].size()*(long long)(bcc[i].size()-1)/2;  99  } 100  } 101         for(int i=1;i<=N;i++){ 102             if(!bccno[i]) 103                 ansn++; 104  } 105         ++kase; 106         printf("Case %d: ",kase); 107         printf("%d %lld\n",ansn,anss); 108  } 109 return 0; 110 }
View Code
相關文章
相關標籤/搜索