首页 > 其他分享 >hszxoj 矿场搭建 [tarjan]

hszxoj 矿场搭建 [tarjan]

时间:2023-12-08 20:22:57浏览次数:32  
标签:tarjan 挖煤 矿场 int 割点 出口 hszxoj vDCC 输入

hszxoj 矿场搭建

  • 题目描述
    原题来自:HNOI 2012
    煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。
    请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。
  • 输入格式
    输入文件有若干组数据,每组数据的第一行是一个正整数n,表示工地的隧道数,接下来的n行每行是用空格隔开的两个整数a和b,表示挖煤点a与挖煤点b由隧道直接连接。输入数据以0结尾。
  • 输出格式
    输入文件中有多少组数据,输出文件中就有多少行。每行对应一组输入数据的结果。
    其中第i行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与 : 之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第i组输入数据至少需要设置几个救援出口,第二个正整数表示对于第i组输入数据不同最少救援出口的设置方案总数。输出格式参照以下输入输出样例。
  • 样例输入
    9
    1 3
    4 1
    3 5
    1 2
    2 6
    1 5
    6 3
    1 6
    3 2
    6
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    0
  • 样例输出
    Case 1: 2 4
    Case 2: 4 1

解析

一个无向图,故他是有几个vDCC组成的,来讨论每一个vDCC。

先考虑一个问题:
割点是一个很重要的点,如果这个这个vDCC里有割点,说明他可以通过这个割点前往别的vDCC里找出口。

但如果这个割点被砸了,就另外需要安装一个出口跑。

  • \(情况1:\)
    在一个vDCC里不存在割点,则需安装2个出口。
    \(why?\)
    若其中一个出口被砸了,需要另一个出口跑。
    image
  • \(情况2:\)
    在一个vDCC中存在一个割点,则需安装1个出口。
    \(why?\)
    前面说过:\(割点\)是一个很重要的点,如果这个这个vDCC里有割点,说明他可以通过这个割点前往别的vDCC里找出口。
    但如果这个割点被砸了,就另外需要安装一个出口跑。
    image
  • \(情况3:\)
    若一个vDCC里有2个及以上个割点,就什么也不用装了。
    比较好理解,参考前面的解释,这个割点被砸了他还有另一个割点可以跑呢。
    image
    \(\Large{参考:}\)
    点双通分量(vDCC)
    割点

代码实现

#include<bits/stdc++.h>
#define int long long 
#define endl '\n'
using namespace std;
const int N=501;
int dfn[N],low[N],n,ans1,ans2,tot,a,b,num,t;
bool cut[N];
vector<int>e[N],dcc[N];
stack<int>s;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool f=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(f?x:~x+1);
}
void clean()
{
    memset(dfn,0,sizeof(dfn)),
    memset(low,0,sizeof(low)),
    memset(cut,0,sizeof(cut)),
    memset(e,0,sizeof(e)),
    memset(dcc,0,sizeof(dcc)),
    ans1=tot=num=0,ans2=1;
}
void tarjan(int x,int fa)
{
	dfn[x]=low[x]=++tot;
	s.push(x);
    int child=0;
	if(x==fa&&e[x].size()==0)
	{
		dcc[++num].push_back(x);
		return ;
	}
	for(int y:e[x])
		if(!dfn[y])
		{
			tarjan(y,fa);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				++num,++child;
                if(x!=fa||child>1) cut[x]=1;
				int z;
				while(z!=y)
					z=s.top(),
					s.pop(),
					dcc[num].push_back(z);
				dcc[num].push_back(x);//与x共同构成一个vDCC
			}
		}
		else low[x]=min(low[x],dfn[y]);
}
signed main()
{
	#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
	while(1)
    {
        read(n);
        if(n==0) return 0;
        clean();
        for(int i=1;i<=n;i++)
            read(a),read(b),
            e[a].push_back(b),
            e[b].push_back(a);  
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i);
        for(int i=1;i<=num;i++)
        {
            int tge=0,l=dcc[i].size();
            if(l==1) continue;
            for(int j=0;j<l;j++) if(cut[dcc[i][j]]) tge++;
            if(tge==0) ans1+=2,ans2*=l*(l-1)/2;
            else if(tge==1) ans1++,ans2*=l-1;
        }
        cout<<"Case "<<++t<<": "<<ans1<<' '<<ans2<<endl;
    }
}

标签:tarjan,挖煤,矿场,int,割点,出口,hszxoj,vDCC,输入
From: https://www.cnblogs.com/Charlieljk/p/17888945.html

相关文章

  • tarjan无向图割点板子
    //无向图割点模板#include<bits/stdc++.h>#defineintlonglong#defineendl'\n'#defineN20001usingnamespacestd;template<typenameTp>inlinevoidread(Tp&x){x=0;registerboolf=1;registercharc=getchar();for(;c&......
  • 【POJ 1144】Network 题解(Tarjan算法求无向图的割点)
    一家电话线公司(TLC)正在建立一个新的电话电缆网络。它们连接由1到N的整数编号的几个位置。没有两个地方的数字相同。这些线路是双向的,总是连接在两个地方,在每一个地方,线路都以电话交换机结束。每个地方都有一个电话交换机。从每个地方可以通过其他地方的线路到达,但不需要直接连接,可......
  • 无向图tarjan
    ·区别于有向图(他的儿子是可能等于他的爸爸的)所以需要这么打tarjan(1,0);voidtarjan(intx,intfa){dfn[x]=low[x]=++tot;q.push(x),ins[x]=1;for(inty:e[x])if(y==fa)continue;//他的儿子是可能等于他的爸爸的elseif(!dfn[y])......
  • hszxoj ATM [tarjan]
    hszxojATM题目描述:$Siruseri$城中的道路都是单向的。不同的道路由路口连接。按照法律的规定,在每个路口都设立了一个$Siruseri$银行的$ATM$取款机。令人奇怪的是,$Siruseri$的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。$Banditji$计划实施$Siruseri$有史以来最......
  • Tarjan 学习笔记
    萌新刚学Tarjan,啥也不会,肯定一堆错,请大佬指正谢谢前置强连通强连通:在不是强连通图的有向图\(G\)内,其顶点\(u\),\(v\)两个方向上都存在有向路径,则\(u\)和\(v\)强连通强连通图:对于有向图\(G\),若\(G\)中任意两个结点连通,则称有向图\(G\)强连通。强连通分量:有向图的极......
  • 离线快速LCA(最近公共祖先) Tarjan算法
    离线快速LCA(最近公共祖先)Tarjan算法前言对于OIer来说,LCA一直是处理树上问题的好帮手,无论是倍增还是树剖都有着优秀的\(\logn\)的复杂度。不过由于我们(数据规模)的上进,需要更快速求LCA,于是就有了……反正之前打死我都不相信这玩意能离线,还能O(1)算法思路首先来一棵树:......
  • tarjan、缩点、删点、删边
    D.CyclicOperations好久没有用tarjan了,今天做一道题,顺便复习一下tarjan是用来求连通性的算法,时间复杂度O(n)。网上关于tarjan的博文很多,我这里就不写了,只是复习一下。这道题很容易想到建边i-a[i]:对于长度是k的环,很显然可以满足;对于长度不是k的环,无论如何都不能......
  • TARJAN复习 求强连通分量、割点、桥
    TARJAN复习求强连通分量、割点、桥目录TARJAN复习求强连通分量、割点、桥强连通分量缩点桥割点感觉之前写的不好,再水一篇博客强连通分量“有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(......
  • 连通性与 Tarjan
    强连通分量和Tarjan强连通分量(StronglyConnectedComponents,SCC),指的是极大的连通子图。tarjan算法,用于求图的强连通分量。dfs生成树有向图的dfs生成树大致分为四种边:树边(treeedge):示意图中以黑色边表示,每次搜索找到一个还没有访问过的结点的时候就形成了一条树边......
  • Tarjan强连通分量详解
    1、简介:在阅读下列内容之前,请务必了解 图论相关概念 中的基础部分。强连通的定义是:有向图G强连通是指,G中任意两个结点连通。强连通分量(StronglyConnectedComponents,SCC)的定义是:极大的强连通子图。这里要介绍的是如何来求强连通分量。2、引入:在介绍该算法之前,先来了解......