zoukankan      html  css  js  c++  java
  • 点双连通分量 [HNOI2012]矿场搭建

      

    问题 F: [HNOI2012]矿场搭建

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

    输入

    输入文件有若干组数据,每组数据的第一行是一个正整数 NN≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S  T,表示挖       与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。

    输出

    输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case  i 之间有空格,:之间无空格,之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。

    样例输入

    9                       1  3                     4  13  51  22  61  56  31  63  26 1  21  32  42  53  63  70 

    样例输出

    Case 1: 2 4Case 2: 4 1

    提示

    Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6)
        用到了点双连通分量,定义是这个连通块通过割点与其它块分开,而割点一旦去掉整个块就不连通了,那么也就和这道题扯上了关系。对于一个点双连通分量,如果他只有一个割点,那他必须建一个(在非割点),不然割点塌了这个点双连通分量就毁了。。如果有两个以上割点,不用建,因为就算一个割点塌了,还可以通过另一个跑掉(狡兔三窟~),也对于没有割点的(就是自己只连自己)必须建两个,如果碰巧你建的点塌了,就又毁掉了。。
        那么就很明确了。只是到底有多少种方法求点双连通分量,我也不知道,但貌似一人一种。。
     
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #define N 500
    #define ll long long
    using namespace std;
    struct node
    {
    	int v,next;
    } lu[N*2+5];
    int zhan[N*2+5];
    int dfn[N*2+5],low[N*2+5],belong[N*2+5];
    int n,m,adj[N*2+5],e,cnt,ji,head;
    ll ans2=1,ans1=0;
    void add(int u,int v){lu[++e].v=v;lu[e].next=adj[u];adj[u]=e;}
    void init()
    {
    	memset(dfn,0,sizeof(dfn));
    	memset(low,0,sizeof(low));
    	memset(adj,0,sizeof(adj));
    	memset(belong,0,sizeof(belong));
    	head=e=ji=0;ans1=0;ans2=1;
    }
    void tarjin(int x)
    {
    	dfn[x]=low[x]=++ji;
    	for(int i=adj[x];i;i=lu[i].next)
    	{
    		int to=lu[i].v;
    		if(dfn[to])
    		    low[x]=min(low[x],dfn[to]);
    		else
    		{
    			tarjin(to);
    			low[x]=min(low[x],low[to]);
    			if(low[to]>=dfn[x])
    			   belong[x]++;
    		}
    	}
    }
    void dfs(int x)
    {
    	low[x]=dfn[x]=++ji;
    	zhan[++head]=x;
    	for(int i=adj[x];i;i=lu[i].next)
    	{
    		int to=lu[i].v;
    		if(dfn[to])
    		    low[x]=min(low[x],dfn[to]);
    		else
    		{
    			dfs(to);
    			low[x]=min(low[x],low[to]);
    			if(low[to]>=dfn[x])
    			{
    				int t,temp=0,size=0;
    				while(1)
    				{
    					t=zhan[head--];
    					if(belong[t]>=2)temp++;
    					size++;
    					if(t==to)break;
    				}
    				t=x;
    				if(belong[t]>=2)temp++;
    				++size;
    				if(!temp)
    				    ans1+=2,ans2*=size*(size-1)/2;
    				else if(temp==1)
    				    ans1++,ans2*=size-1;
    			}
    		}
    	}
    }
    int yjn()
    {
    //	freopen("bzoj_2730.in","r",stdin);
    //	freopen("bzoj_2730.out","w",stdout);
    	int u=0;
    	while(++u)
    	{
    		scanf("%d",&m);
    		if(m==0)break;
    		init();
    		int x,y;
    		for(int i=1;i<=m;i++)
    		{
    			scanf("%d%d",&x,&y);
    			add(x,y);
    			add(y,x);
    			n=max(n,max(x,y));
    		}
    		for(int i=1;i<=n;i++)
    		    if(!dfn[i])
    		    	tarjin(i);
    		    else
    		        belong[i]++;
    		memset(dfn,0,sizeof(dfn));
    		ji=0;
    		for(int i=1;i<=n;i++)
    		    if(!dfn[i])
    		    	dfs(i);
    		cout<<"Case "<<u<<": ";    
            cout<<ans1<<' '<<ans2<<endl;    
    	}
    }
    int qty=yjn();
    int main(){;}

  • 相关阅读:
    字符序列(characts)
    装载问题(load)
    哈密顿路
    犯罪团伙
    回溯算法
    维修机器人
    旅行计划
    皇后游戏
    运输
    亲身实测可用的java实现wordxlsxpdf文件下载功能
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632713.html
Copyright © 2011-2022 走看看