• P3225 [HNOI2012]矿场搭建 题解


    题目大意

    给定一个由隧道连接挖煤点的无向图,保证在任何一个工地发生坍塌后,其他的挖煤点的工人都有一条道路通向救援出口

    求最少的救援出口处和总方案数

    P3225 [HNOI2012]矿场搭建

    问题求解

    显然

    如果没有割点

    至少需要建立两个出口

    从任意非割点的地方选择两个点建立

    如果这个分组只有一个割点

    只需要在分组内设立一个出口

    可以设立在任意一个非割点的地方

    如果有两个及以上个割点,则无需建立,可以直接到达其他联通块

    代码实现

    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int maxn=505;
    int T,N,M,K,cnt,Ans1,c[maxn],low[maxn],dfn[maxn],root;
    LL Ans2;
    vector<int> e[maxn],DCC[maxn];
    stack<int> s;
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }
    void Tarjan(int x){
    	int fa=0; s.push(x);
    	low[x]=dfn[x]=++cnt;
    	for(int j=0;j<e[x].size();j++){
    		int y=e[x][j];
    		if(!dfn[y]){
    			Tarjan(y);
    			low[x]=min(low[x],low[y]);
    			if(low[y]>=dfn[x]){
    				fa++;K++;
    				if(x!=root||fa>1)c[x]=1;
    				DCC[K].push_back(x);
    				int z=0;
    				do{
    					DCC[K].push_back(z=s.top());s.pop();
    				}while(z!=y);
    			}
    		}
    		else low[x]=min(low[x],dfn[y]);
    	}
    }
    int main(){
    	freopen("P3225.in","r",stdin);
    	freopen("P3225.out","w",stdout);
    	while(true){
    		N=read();if(!N)break;
    		while(!s.empty()) s.pop();
    		for(int i=1;i<=N;i++) e[i].clear();
    		for(int i=1;i<=K;i++) DCC[i].clear();
    		M=K=Ans1=cnt=0;Ans2=1;
    		memset(low,0,sizeof low);
    		memset(c,0,sizeof c);
    		memset(dfn,0,sizeof dfn);
    		for(int i=1;i<=N;i++){
    			int x=read(),y=read();
    			e[x].push_back(y);e[y].push_back(x);
    			M=max(M,x);M=max(M,y);
    		}
    		for(int i=1;i<=M;i++)if(!dfn[i]){
    			root=i;Tarjan(i);
    		}
    		for(int i=1;i<=K;i++){
    			int num=0,cnt=DCC[i].size();
    			for(int j=0;j<cnt;j++)num+=c[DCC[i][j]];
    //			for(int j=0;j<cnt;j++)printf("%d ",DCC[i][j]);
    			printf("
    ");
    			if(num==1)Ans1++,Ans2*=cnt-1;
    			if(num==0)Ans1+=2,Ans2*=cnt*(cnt-1)>>1;
    		}
    //		printf("%d %lld
    ",Ans1,Ans2);
    		printf("Case %d: %d %lld
    ",++T,Ans1,Ans2);
    	}
    	return 0;
    }
    

    关于其他

    貌似有三倍经验???

  • 相关阅读:
    课堂小组讨论结果
    Beta阶段项目总结
    第二次冲刺团队绩效评估
    第二次冲刺-站立会议10
    第二次冲刺-站立会议09
    第二次冲刺-站立会议08
    第二次冲刺-站立会议07
    第二次冲刺-站立会议06
    第二次冲刺-站立会议05
    第二次冲刺-站立会议04
  • 原文地址:https://www.cnblogs.com/martian148/p/15177346.html
Copyright © 2020-2023  润新知