Description
煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。
Solution
警察叔叔就是这道Dog Birth题搞了我一个下午
n的范围是500可是怎么看我的做法都是
O(n)
的==
首先对于那些不是割点的点我们没必要管他是不是
所以我们可以先tarjan跑出割点。
然后把割点都删了,看看多出多少联通块。
然后扫描联通块,如果某联通块与大于等于2个割点相连,那么这个联通块多半是废了就没意义了是不是
然后如果只与一个割点相连,那么答案可能性要乘上联通块的size,块数要++
所以
O(n)
就够了呀==
割(智)点(商)敲(不)错(够)调死我了==
现在重申一下割点的得到方法:
首先像一般tarjan那样,得到pre和lowlink数组。
然后对于以某节点
v
,如果它有一个子节点
不知为何调了很久?
Code
/**************************************************************
Problem: 2730
User: bblss123
Language: C++
Result: Accepted
Time:4 ms
Memory:1308 kb
****************************************************************/
#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<vector>
using namespace std;
typedef long long ll;
const int M=505;
int n,m,txt=0;
int dfs_clock,pre[M],lowlink[M],sccid[M],allc;
inline void Min(int &a,int b){if(a>b)a=b;}
inline void Max(int &a,int b){if(a<b)a=b;}
#define vec vector<int>
#define pb push_back
vec G[M];
bool mark[M];
int flag[M];
void predfs(int v,const int &rt){
pre[v]=lowlink[v]=++dfs_clock;
int p=mark[v]=0;
for(int i=0;i<G[v].size();++i){
int to=G[v][i];
if(pre[to])Min(lowlink[v],pre[to]);
else{
predfs(to,rt),Min(lowlink[v],lowlink[to]);
mark[v]|=lowlink[to]>=pre[v];
++p;
}
}
if(v==rt&&p<=1)mark[v]=0;
}
inline void rd(int &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
int sz,cnt;
void dfs(int v,const int &c){
flag[v]=c;
++sz;
for(int i=0;i<G[v].size();++i){
int to=G[v][i];
if(flag[to]==c)continue;
if(mark[to]){
flag[to]=c,++cnt;
continue;
}
dfs(to,c);
}
}
inline void Init(){
memset(mark,0,sizeof(mark));
memset(flag,0,sizeof(flag));
memset(pre,0,sizeof(pre));
memset(lowlink,0,sizeof(lowlink));
memset(sccid,0,sizeof(sccid));
for(int i=1;i<=n;++i)G[i].clear();
dfs_clock=0,allc=0;
}
inline void gao(){
n=0;
for(int i=1,a,b;i<=m;++i){
rd(a),rd(b);
G[a].pb(b),G[b].pb(a);
Max(n,a),Max(n,b);
}
for(int i=1;i<=n;++i)
if(!pre[i])predfs(i,i);
int res=0;ll ans=1;
for(int i=1;i<=n;++i){
if(mark[i]||flag[i])continue;
sz=cnt=0;
dfs(i,i);
if(cnt>=2)continue;
ans*=sz,++res;
}
if(res==1)printf("Case %d: 2 %d\n",++txt,n*(n-1)>>1);
else printf("Case %d: %d %lld\n",++txt,res,ans);
Init();
}
int main(){
for(;scanf("%d",&m),m;)gao();
}