(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
目录
题意:传送门
原题目描述在最下面。
m条无向边链接两个矿洞。在某些矿洞设置安全出口,使得无论哪一个点毁坏,所有的工人都能逃到安全出口。求设置的安全出口的最小数量
ans1
a
n
s
1
,以及数量方案
ans2
a
n
s
2
.
超级无敌的类似这一题:传送门。那个题的毁坏一条边,本题是毁坏一个点。
思路:
垃圾题目毁我青春!
找了一下午的bug,换了两种邻接表都没过。结果发现是
n
n
没有置零,我去~
方法一:
标记所有的割点。然后暴力所有没有被访问过的不是割点的点,统计该点双联通分量内割点的数量
cut
c
u
t
,和非割点的数量
cnt
c
n
t
。如果
cnt=1
c
n
t
=
1
,
ans1++
a
n
s
1
+
+
,
ans2∗=cnt
a
n
s
2
∗
=
c
n
t
;如果
cnt=2
c
n
t
=
2
,
ans1+=2,ans2∗=(cnt∗(cnt−1)/2)
a
n
s
1
+
=
2
,
a
n
s
2
∗
=
(
c
n
t
∗
(
c
n
t
−
1
)
/
2
)
。
方法二:
同样先求出所有的割点,然后再来一遍
tarjan
t
a
r
j
a
n
,点双联通分量缩点(该联通分量最后一个点不
pop
p
o
p
出栈),统计该联通分量内割点的数量
cut
c
u
t
,和非割点的数量
cnt
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;
}