洛谷-P3225 [HNOI2012]矿场搭建

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

目录

题意:传送门

 原题目描述在最下面。
 m条无向边链接两个矿洞。在某些矿洞设置安全出口,使得无论哪一个点毁坏,所有的工人都能逃到安全出口。求设置的安全出口的最小数量 a n s 1 ,以及数量方案 a n s 2 .

 超级无敌的类似这一题:传送门。那个题的毁坏一条边,本题是毁坏一个点。

思路:

垃圾题目毁我青春!
 找了一下午的bug,换了两种邻接表都没过。结果发现是 n 没有置零,我去~

方法一:
 标记所有的割点。然后暴力 d f s 所有没有被访问过的不是割点的点,统计该点双联通分量内割点的数量 c u t ,和非割点的数量 c n t 。如果 c n t = 1 a n s 1 + + a n s 2 = c n t ;如果 c n t = 2 a n s 1 + = 2 , a n s 2 = ( c n t ( c n t 1 ) / 2 )

方法二:
 同样先求出所有的割点,然后再来一遍 t a r j a n ,点双联通分量缩点(该联通分量最后一个点不 p o p 出栈),统计该联通分量内割点的数量 c u t ,和非割点的数量 c n t 。计算公式同上。


AC代码:

#include<bits/stdc++.h>
#define mme(a,b) memset((a),(b),sizeof((a)))
#define fuck(x) cout<<"* "<<x<<"\n"
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int N = 1e4+5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
struct lp{
  int v,nex;
}cw[N];
int dfn[N],low[N],inde,vis[N],qltNum,head[N],tot;
int stak[N*100],top;
int iscut[N],belong_num[N];
int cut,cnt,col,rt;
LL ans1,ans2;
void dfs1(int u,int Fa){
  dfn[u]=low[u]=++inde;
  int son=0;
  for(int i=head[u];~i;i=cw[i].nex){
    int v = cw[i].v;
    if(v==Fa)continue;
    if(!dfn[v]){
      dfs1(v,u);
      son++;
      low[u]=min(low[u],low[v]);
      if(low[v]>=dfn[u]){
        iscut[u]=1;
      }
    }else low[u]=min(low[u],dfn[v]);
  }
  if(son==1&&u==rt)iscut[u]=0;
}
void dfs2(int u,int Fa){
  vis[u]=col;
  cnt++;
  for(int i=head[u];~i;i=cw[i].nex){
    int v = cw[i].v;
    if(v==Fa)continue;
    if(vis[v]>=col)continue;
    if(iscut[v]){
      cut++;vis[v]=col;
    }else {
      dfs2(v,u);
    }
  }
}
void tarjan(){
  for(int i=1;i<=n;++i){
    if(!dfn[i]){
      rt=i;
      dfs1(i,-1);
    }
  }
  ans1=0;ans2=1;
  mme(vis,0);
  for(int i=1;i<=n;++i){
    cnt=cut=0;col++;
    if(vis[i]==0&&iscut[i]==0){
      dfs2(i,-1);
      if(cut==1){
        ans1++;
        ans2*=cnt;
      }else if(cut==0){
        if(cnt==1){
          ans1++;
        }else{
          ans1+=2;
          ans2=cnt*(cnt-1)/2*ans2;
        }
      }
    }
  }
}
inline void init(){
  mme(iscut,0);mme(belong_num,0);
  mme(dfn,0);mme(low,0);mme(vis,0);
  top=inde=qltNum=col=0;
  mme(head,-1);tot=-1;
}
inline void add(int u,int v){
  cw[++tot].v=v;cw[tot].nex=head[u];
  head[u]=tot;
  cw[++tot].v=u;cw[tot].nex=head[v];
  head[v]=tot;
}
int main(){
  int tc=0;
  while(~scanf("%d", &m)&&m){
    init();
    n=0;
    for(int i=0,u,v;i<m;++i){
      scanf("%d%d",&u,&v);
      n=max(n,max(u,v));
      add(u,v);
    }
    tarjan();
    printf("Case %d: %lld %lld\n", ++tc, ans1,ans2);
  }
  return 0;
}


原题目描述:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81315580
今日推荐