给出
n
≤
1
e
3
n\leq1e3
n≤1e3个点的无向图,你可以在每个点选择放置避难所。然后求问所有的方案满足:1.对于任何一点被破坏,剩下的点能都走到避难所。2.放置避难所的数目最少。
如果这个点放置在非割点的位置,那么不会对图的连通性产生影响。
所以先求出图中所有的割点,这样与每个割点相连接的就是一个连通块。
1.如果这个连通块本身与
0
0
0个割点相连,必须要放置
2
2
2个。
2.如果这个连通块本身与
1
1
1个割点相连,任选一个位置放置。
3.如果这个连通块本身与超过
1
1
1个割点相连,不必放置。
分类统计答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e3+7;
vector<int> go[N];
int dfn[N],low[N],tim=0;
bool cut[N];
int vis[N];
int T=0;
void clear() {
for(int i=1;i<=1000;i++)
go[i].clear();
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(cut,0,sizeof(cut));
tim=0;
memset(vis,0,sizeof(vis));
T=0;
}
void tarjan(int u,int rt) {
dfn[u]=low[u]=++tim;
int ch=0;
for(auto &v:go[u]) {
if(!dfn[v]) {
tarjan(v,rt);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]&&u!=rt) cut[u]=1;
if(u==rt) ++ch;
}
low[u]=min(low[u],dfn[v]);
}
if(u==rt&&ch>=2) cut[u]=1;
}
int sz=0,cu=0;
void dfs(int u) {
vis[u]=T;
if(cut[u]) { ++cu; return; }
else ++sz;
for(auto &v:go[u]) {
if(vis[v]!=T)
dfs(v);
}
}
int kase=0;
int main() {
int m,n=0;
while(scanf("%d",&m)!=EOF) {
n=0;
if(m==0) break;
clear();
for(int i=1;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
go[u].push_back(v);
go[v].push_back(u);
n=max(n,u),n=max(n,v);
}
for(int i=1;i<=n;i++) {
if(!dfn[i]) {
tarjan(i,i);
}
}
ll ans1=0,ans2=1;
for(int i=1;i<=n;i++) {
if(!cut[i]&&!vis[i]) {
T++;
sz=cu=0;
dfs(i);
if(cu==0) ans1+=2,ans2*=1ll*sz*(sz-1)/2;
else if(cu==1) ans1+=1,ans2*=sz;
}
}
printf("Case %d: %lld %lld\n",++kase,ans1,ans2);
}
return 0;
}