2018.10.30【HNOI2012】【洛谷P3225】【BZOJ2730】矿场搭建(割点)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83536140

BZOJ传送门

洛谷传送门


解析:

首先,工人不能逃到其他联通块的情况就是割点坍塌了。如果其他点坍塌是不会对连通性有影响的(即工人能够逃到其他连通分量里面的出口)。

那么先求出所有割点。然后看每一个点双内部的情况来讨论:
1.有不少于2个割点,这时候任何一个割点塌了都可以到达其他联通分量里面的割点,不需要新建。
2.有一个割点,显然这个割点塌了就会使这个联通分量gg,所以这个分量内部需要新建一个救援出口,并且任何非割点的点都可以作为出口。
3.没有割点,说明这是一个与其他联通分量完全隔绝的分量,需要建两个出口,避免一个塌了就gg,任何点都可以作为出口。

就这样推一下就行了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs int N=505;
int last[N<<1],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}

int dfn[N],low[N],dfs_clock;
bool cut[N];

inline void tarjan(int u,int root){
	dfn[u]=low[u]=++dfs_clock;
	cut[u]=false;
	int son=0;
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
		if(!dfn[v]){
			tarjan(v,root);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&u!=root)cut[u]=true;
			++son;
		}
		low[u]=min(low[u],dfn[v]);
	}
	if(son>1&&u==root)cut[u]=true;
}

int idx;
ll ncnt,ccnt;//notcutcnt cutcnt
int vis[N];

inline void dfs(int u){
	vis[u]=idx;
	++ncnt;
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
		if(cut[v]&&vis[v]!=idx){
			++ccnt;
			vis[v]=idx;
		}
		if(!vis[v]){
			dfs(v);
		}
	}
}

ll cnt,mcnt;
int n,m,kase;
signed main(){
	while(m=getint()){
		++kase;
		ecnt=0;n=0;cnt=0;mcnt=1;
		memset(last,0,sizeof last);
		memset(dfn,0,sizeof dfn);
		memset(vis,0,sizeof vis);
		for(int re i=1;i<=m;++i){
			int u=getint(),v=getint();
			addedge(u,v);
			n=max(n,max(u,v));
		}
		for(int re i=1;i<=n;++i){
			if(!dfn[i])tarjan(i,i);
		}
		for(int re i=1;i<=n;++i){
			if(!cut[i]&&!vis[i]){
				++idx;
				ncnt=ccnt=0;
				dfs(i);
				if(ccnt==0){
					cnt+=2;
					mcnt*=ncnt*(ncnt-1)>>1;
				}
				if(ccnt==1){
					cnt+=1;
					mcnt*=ncnt;
				}
			}
		}
		cout<<"Case "<<kase<<": "<<cnt<<" "<<mcnt<<"\n";
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83536140
今日推荐