P3225 [HNOI2012]矿场搭建

https://www.luogu.org/problemnew/show/P3225

用Tarjan跑出割点,然后DFS搜索所有的联通快

计算每一个联通快中的割点数目

分类讨论:

如果没有割点

至少需要建立两个出口

从任意非割点的地方选择两个点建立

如果这个分组只有一个割点

只需要在分组内设立一个出口

可以设立在任意一个非割点的地方

如果有两个及以上个割点,则无需建立,可以直接到达其他联通块

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 using namespace std;
  6 inline int read(){
  7     int sum=0,x=1;
  8     char ch=getchar();
  9     while(ch<'0'||ch>'9'){
 10         if(ch=='-')
 11             x=0;
 12         ch=getchar();
 13     }
 14     while(ch>='0'&&ch<='9')
 15         sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
 16     return x?sum:-sum;
 17 }
 18 inline void write(int x){
 19     if(x<0)
 20         putchar('-'),x=-x;
 21     if(x>9)
 22         write(x/10);
 23     putchar(x%10+'0');
 24 }
 25 typedef long long ll;
 26 const int M=520;
 27 ll ans1,ans2;
 28 int n,m;
 29 ll tot,cnt,root,child,liantong,vnum,cutnum;
 30 struct node{
 31     int v,nextt;
 32 }e[M*M];
 33 int vis[M],dfn[M],low[M],head[M],cut[M]; 
 34 void tarjan(int u,int f){
 35     dfn[u]=low[u]=++cnt;
 36     for(int i=head[u];~i;i=e[i].nextt){
 37         int v=e[i].v;
 38         if(!dfn[v]){
 39             tarjan(v,u);
 40             low[u]=min(low[u],low[v]);
 41             if(low[v]>=dfn[u]){
 42                 if(u!=root)
 43                     cut[u]=true;
 44                 else
 45                     child++;
 46             }
 47         }
 48         else if(v!=f) 
 49             low[u]=min(low[u],dfn[v]);
 50     }
 51 }
 52 void dfs(int u){
 53     vis[u]=liantong;
 54     vnum++;
 55     for(int i=head[u];~i;i=e[i].nextt){
 56         int v=e[i].v;
 57         if(cut[v]&&vis[v]!=liantong){
 58             vis[v]=liantong;
 59             cutnum++;
 60         }
 61         if(!vis[v])
 62             dfs(v);
 63     }
 64 }
 65 void addedge(int u,int v){
 66     e[tot].v=v;
 67     e[tot].nextt=head[u];
 68     head[u]=tot++;
 69 }
 70 void init(){
 71     memset(head,-1,sizeof(head));
 72     tot=0;
 73     cnt=0;
 74     ans1=0;
 75     ans2=1;
 76     vnum=cutnum=0;
 77     liantong=0;
 78     n=0;
 79     memset(vis,0,sizeof(vis));
 80     memset(cut,0,sizeof(cut));
 81     memset(dfn,0,sizeof(dfn));
 82     memset(low,0,sizeof(low));
 83 }
 84 int main(){
 85     int t=1;
 86     while(cin>>m){
 87         if(m==0)
 88             break;
 89         init();
 90         
 91         while(m--){
 92             int u,v;
 93             cin>>u>>v;
 94             addedge(u,v);
 95             addedge(v,u);
 96             n=max(u,max(n,v));
 97         }
 98         
 99         for(int i=1;i<=n;i++){
100             if(!dfn[i]){
101                 child=0,root=i;
102                 tarjan(i,i);
103                 if(child>=2)
104                     cut[i]=true;
105             }
106         }
107         for(int i=1;i<=n;i++){
108             if(!vis[i]&&!cut[i]){
109                 ++liantong;
110                 vnum=0,cutnum=0;
111                 dfs(i);
112                 //cout<<"!!"<<vnum<<endl;
113                 if(cutnum==0){
114                     ans1+=2;
115                     ans2*=vnum*(vnum-1)/2;
116                 }
117                 else if(cutnum==1){
118                     ans1+=1;
119                     ans2*=vnum;
120                 }
121             }
122         }
123         printf("Case %d: %lld %lld\n",t++,ans1,ans2);
124     }
125     return 0;
126 }
View Code

 

posted @ 2019-06-19 22:27  starve_to_death  阅读(127)  评论(0编辑  收藏  举报