zoukankan      html  css  js  c++  java
  • BZOJ2730 [HNOI2012]矿场搭建[点双连通分量]

    看到删去一个点,需要剩下的都和关键点连通,有端联想到找点双,因为他怎么删点都是连通的。

    对于一个孤立的点双,至少要设两个关键点。

    如果两个点双以一个割点连接,假设断掉这个割点,两个块至少要各设一个关键点。类推,所以对于所有含有一个割点的点双,至少要包含非割点的一个关键点。

    如果一个点双上有好多个割点,可以不设点,因为把图看成缩掉点双的一棵树,有一个割点的点双一定在叶子处,有多个割点的点双因为有许多树枝,删掉一个,一定可以仍与某一方的叶子(也就是位于叶子处的点双中的关键点)连通,所以不要设。

    这样,讨论完毕,统计方案也就很好搞了。

    注意一点:孤立点要特判,因为他只要设一个点。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #include<map>
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef unsigned long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1000+7;
    24 map<int,int> mp;
    25 struct thxorz{int to,nxt;}G[N];
    26 int Head[N],tot;
    27 int n,m,ans,T;
    28 ll typ;
    29 inline void Addedge(int x,int y){
    30     G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot;
    31     G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot;
    32 }
    33 #define y G[j].to
    34 vector<int> dcc[N];
    35 int dfn[N],low[N],stk[N],cut[N],cnt,rt,Top,dcnt;
    36 void tarjan(int x){
    37     dfn[x]=low[x]=++cnt;int chd=0;
    38     if(x==rt&&!Head[x]){dcc[++dcnt].push_back(x);return;}
    39     stk[++Top]=x;
    40     for(register int j=Head[x];j;j=G[j].nxt){
    41         if(!dfn[y]){
    42             ++chd;tarjan(y);MIN(low[x],low[y]);//forget MIN...
    43             if(low[y]==dfn[x]){//or low[y]>=dfn[x]
    44                 if(x==rt&&chd>=2||x^rt)cut[x]=1;
    45                 int tmp;++dcnt;
    46                 do tmp=stk[Top--],dcc[dcnt].push_back(tmp);while(tmp^y);
    47                 dcc[dcnt].push_back(x);
    48             }
    49         }
    50         else MIN(low[x],dfn[y]);
    51     }
    52 }
    53 #undef y
    54 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    55     while(read(m),m){
    56         mp.clear();n=ans=0;typ=1;
    57         memset(Head,0,sizeof Head);tot=0;
    58         for(register int i=1,x,y;i<=m;++i){
    59             read(x),read(y);
    60             if(mp.find(x)==mp.end())mp[x]=++n;
    61             if(mp.find(y)==mp.end())mp[y]=++n;
    62             Addedge(mp[x],mp[y]);
    63         }
    64         memset(dfn,0,sizeof dfn),memset(low,0,sizeof low),memset(cut,0,sizeof cut);dcnt=cnt=0;
    65         for(register int i=1;i<=n;++i)if(!dfn[i])Top=0,rt=i,tarjan(i);
    66         for(register int i=1,tt=0,siz;i<=dcnt;++i,tt=0){
    67             for(register int j=0;j<dcc[i].size();++j)if(cut[dcc[i][j]])++tt;
    68             siz=dcc[i].size();
    69             if(siz==1)++ans;
    70             else if(!tt)ans+=2,typ*=siz*(siz-1)/2;
    71             else if(tt==1)++ans,typ*=(siz-1);
    72             dcc[i].clear();
    73         }
    74         printf("Case %d: %d %llu
    ",++T,ans,typ);
    75     }
    76     return 0;
    77 }
    View Code

    智障WA:line42的MIN漏写了。。果然tarjan还是不熟练啊。

    总结:遇到删点和连通性联系在一起的问题时多往点双上想一想,当然凡是点双都要考虑比较特殊的情况,如:2个点,以及孤立点。

  • 相关阅读:
    B
    A
    P1057 传球游戏
    P1702 突击考试
    P1394 山上的国度
    P2117 小Z的矩阵
    P1510 精卫填海
    P1294 高手去散步
    P1071 潜伏者
    保留
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11713451.html
Copyright © 2011-2022 走看看