LA5135图论+ 割点性质运用

  1 /*
  2 LA5135图论
  3 割点性质运用
  4 
  5 关键:割顶出设置逃生点是不划算的。
  6 这道题的思路算是比较简单,没有推导证明的成分,是BCC性质的运用
  7 注意,当整张图是BCC时,至少要设置两个逃生点,这个也算是考点,开始没想到,下次注意
  8 */
  9 #include <stdio.h>
 10 #include <stdlib.h>
 11 #include <string.h>
 12 #include <math.h>
 13 #include <ctype.h>
 14 #include <string>
 15 #include <iostream>
 16 #include <sstream>
 17 #include <vector>
 18 #include <queue>
 19 #include <stack>
 20 #include <map>
 21 #include <list>
 22 #include <set>
 23 #include <algorithm>
 24 #define rec(i,n) for(int i=1;i<=n;i++)
 25 #define INF 0x3f3f3f3f
 26 using namespace std;
 27 
 28 const int maxn = 101000 ;
 29 struct edge
 30 {
 31     int u,v,cap,pre;//cap表示花费
 32     edge(int u=0,int v=0):u(u),v(v){}
 33 }Edge[maxn];//注意开两倍的边
 34 int head[maxn],next[maxn],nedge;//表示读入的边的个数
 35 void addedge(int u,int v)
 36 {
 37     Edge[++nedge]=edge(u,v);//边从1开始编号
 38     next[nedge]=head[u];
 39     head[u]=nedge;
 40 }
 41 void edgeinit()//添边之前要初始化
 42 {
 43     nedge=0;
 44     memset(head,-1,sizeof(head));
 45 }
 46 int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
 47 vector<int> bcc[maxn];
 48 stack<edge>S ;
 49 
 50 int dfs(int u,int fa)
 51 {
 52     int lowu=pre[u]=++dfs_clock;
 53     int child=0;
 54     for(int i=head[u];i!=-1;i=next[i])
 55     {
 56         int v=Edge[i].v;
 57         edge e=(edge){u,v};
 58         if (!pre[v])
 59         {
 60             S.push(e);
 61             child++;
 62             int lowv=dfs(v,u);//这时,u是父节点
 63             lowu=min(lowu,lowv);
 64             if (lowv>=pre[u])
 65             {
 66                 iscut[u]=true;
 67                 bcc_cnt++;bcc[bcc_cnt].clear();
 68                 for(;;)
 69                 {
 70                     edge x=S.top();S.pop();
 71                     if(bccno[x.u]!=bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;}
 72                     if(bccno[x.v]!=bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;}
 73                     if(x.u==u&&x.v==v) break;
 74                 }
 75             }
 76         }
 77         else if (pre[v]<pre[u] && v!=fa)
 78         {
 79             S.push(e);
 80             lowu=min(lowu,pre[v]);
 81         }
 82     }
 83     if(fa<0 && child==1) iscut[u]=0;
 84     return lowu;
 85 }
 86 
 87 void find_bcc(int n)//n是定点个数
 88 {
 89     memset(pre,0,sizeof(pre));
 90     memset(iscut,0,sizeof(iscut));
 91     memset(bccno,0,sizeof(bccno));
 92     dfs_clock=bcc_cnt=0;
 93     for(int i=1;i<=n;i++)
 94     {
 95         if(!pre[i]) dfs(i,-1);
 96     }
 97 }
 98 void solve(int cas,int m)
 99 {
100     long long n1=0,n2=1;
101     if (bcc_cnt==1) n1=2,n2=(long long)bcc[1].size()*(bcc[1].size()-1)/2;
102     else
103     {
104         for(int i=1;i<=bcc_cnt;i++)//枚举每个bcc
105         {
106             int cnt=0;//一个bcc中割顶的个数是1或0
107             for(int j=0;j<bcc[i].size();j++)
108             if(iscut[bcc[i][j]]) cnt++;
109             if(cnt==1) n1++,n2=n2*(long long)(bcc[i].size()-1);
110         }
111     }
112     cout<<"Case "<<cas<<": "<<n1<<" "<<n2<<endl;
113     return;
114 }
115 int main()
116 {
117     int n,cas=0;
118 
119     while(cin>>n && n!=0)
120     {
121         cas++;
122         edgeinit();
123         int m=0;
124         for(int i=1;i<=n;i++)
125         {
126             int u,v;
127             cin>>u>>v;
128             addedge(u,v);addedge(v,u);
129             m=max(m,u);m=max(m,v);//最大的点
130         }
131         find_bcc(m);
132         solve(cas,m);
133     }
134     return 0;
135 }

 

posted @ 2014-02-26 21:03  little_w  阅读(500)  评论(0编辑  收藏  举报