Luogu_P3225 [HNOI2012]矿场搭建
割点
题目链接
这种把点拿走明显就和割点有关系
那么就先求割点
求完割点然后???
首先dfs每个割点分开的连通块
如果这个连通块没有割点,必然要两个出口
假如有这个联通有一个割点那么一定要放一个,因为假如割点塌了就需要这个点了
假如有两个或者更多那么就不需要了,因为哪怕塌了割点也可以从别的割点走
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1010;
int tim,n,m,head[maxn],tot,cnt,low[maxn],dfn[maxn],cut[maxn],rt,vis[maxn],cct,siz,cs;
struct node{
int nxt,to;
#define nxt(x) e[x].nxt
#define to(x) e[x].to
}e[maxn<<1];
inline void add(int from,int to){
to(++tot)=to;nxt(tot)=head[from];head[from]=tot;
}
void tarjan(int x){
dfn[x]=low[x]=++cnt;
int fl=0;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]){
fl++;
if(x!=rt || fl>1) cut[x]=1;
}
}else low[x]=min(low[x],dfn[y]);
}
}
void dfs(int x){
vis[x]=tim;
if(cut[x]) return;
siz++;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(cut[y] && vis[y]!=tim) cct++,vis[y]=tim;
if(!vis[y]) dfs(y);
}
}
int main()
{
while(scanf("%d",&m) && m){
memset(head,0,sizeof(head));memset(e,0,sizeof(e));siz=tim=cnt=n=tot=cct=0;
memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(cut,0,sizeof(cut));memset(vis,0,sizeof(vis));
for(int x,y,i=1;i<=m;i++){
scanf("%d%d",&x,&y);add(x,y);add(y,x);n=max(n,y);n=max(n,x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) rt=i,tarjan(i);
ll ans1=0,ans2=1;
for(int i=1;i<=n;i++)
if(!vis[i] && !cut[i]){
tim++;cct=siz=0;
dfs(i);
if(!cct)
ans1+=2,ans2*=siz*(siz-1)/2;
if(cct==1)
ans1++,ans2*=siz;
}
printf("Case %d: %lld %lld
",++cs,ans1,ans2);
}
return 0;
}