首页 > 其他分享 >题解 P3225 [HNOI2012] 矿场搭建

题解 P3225 [HNOI2012] 矿场搭建

时间:2023-04-28 21:24:28浏览次数:46  
标签:一个点 点双 int 题解 ll 割点 HNOI2012 low P3225

解析

传送门

一道简单的tarjan题

题意:在无向图中找一些点,这些点组成的的点集记为\(V\) ,使得去掉任意一个点,剩下的每一个点都可以到达\(V\)中任意一个点,求点集\(V\)的大小的最小值及其方案数。

去掉一个点,很自然的联想到割点,那么考虑一下割点在不在备选集合中。

1234

如图,显然可以看出,在割点上设立出口是劣的,因此我们永远不会在割点上设立出口

既然不在割点上设立出口,那我们就把目光投向点双。

graph (3)

根据点双的定义,无论我们去掉哪一个点,剩下的点都可以相互到达。

因此我们只要在一个点双内设立两个出口就可以保证题目要求,方案数为\(\tbinom{n}{2}\)(证明很简单,分类讨论即可)

注意:刚才我们讨论的是一个点双,现在范围扩大一下

graph (4)

现在两个点双各被一个割点(加粗的黑点)相连了,每个点双内需要设立的出口数就变成了一个,Why?

  1. 假如去掉的点是割点

    graph (5)

    根据点双的定义,每个点双内部的点都能到达自己的出口。

  2. 假如去掉的点是点双内部的一个出口(这里假设为\(2\))

    graph (6)

    虽然\(1\),\(3\)到达不了\(2\),但它们可以借助割点组成的“桥”来到达其他点。(这里的桥仅作比喻用)

如此,便可以得出:一个点双与一个割点相连只要设立一个出口,方案数为\(n\)

一个点双与两个及以上割点相连的情形是简单的graph (7)

点集\(\{1,2,3,4\}\)组成的点双与两个割点相连,这意味着无论断哪个割点,这个点双内的剩余点都可以沿着其他割点走到别的点双内的出口。

有人一定要说:那我每个点双都与两个割点不就好了吗?

答案显然是不行

在只保留割点的情况下,所有的割点构成一棵无根树

graph (8)

根据割点的定义,每个割点都至少与一个点双相连

考虑度为\(1\)的节点

12345

这个黑色圆圈代表的点双只要再连任意一条道割点的边,就会形成一个环,而这与割点的定义不符。

由此便可以写代码了,方案数按照乘法原理一个一个一个相乘就好了

代码

总算说完又臭又长的解析了,如果很的话直接看代码就好了

注意割点不能选,算点双大小时不能把割点带上

code
// Problem: P3225 [HNOI2012]矿场搭建
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3225
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define db double 
using namespace std;
const ll INF=1e18+7;
const db eps=1e-9;
const int MAXN=1e3+3;
ll n,m;
ll ans,ANS;
ll CNT,low[MAXN],dfn[MAXN],cnt;
vector<ll> graph[MAXN];
ll T,cut[MAXN],flag[MAXN],size,CUT;
void tarjan(int u,int fa){
	low[u]=dfn[u]=++cnt;
	int child=0;
	for(auto v:graph[u]){
		if(v==fa) continue;
		if(!dfn[v]){
			child++;
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&fa!=u){
				cut[u]=1;
			}
		}
		else{
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(u==fa&&child>=2){
		cut[u]=1;
	}
}

void clear(){
	ans=1,ANS=CNT=cnt=0;
	for(int i=1;i<=n;i++){
		graph[i].clear();
	}
	memset(dfn,0,sizeof(dfn));	
	memset(low,0,sizeof(low));
	memset(flag,0,sizeof(flag));
	memset(cut,0,sizeof(cut));
}
void dfs(int u){
	flag[u]=CNT;
	size++;
	for(auto v:graph[u]){
		if(flag[v]!=CNT&&cut[v]==1){
			CUT++;
			flag[v]=CNT;
		}
		if(flag[v]==0){
			dfs(v);
		}
	}
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    while(1){
    	clear();
    	T++;
    	cin>>m;
    	if(m==0){
    		break;
    	}
    	n=0;
    	for(int i=1;i<=m;i++){
    		ll u,v;
    		cin>>u>>v;
    		graph[u].push_back(v);
    		graph[v].push_back(u);
    		n=max(n,max(u,v));
    	}
    	for(int i=1;i<=n;i++){
    		if(!dfn[i]){
    			tarjan(i,i);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		if(!cut[i]&&!flag[i]){
    			size=CUT=0;
    			CNT++;
    			dfs(i);
    			if(CUT==0){
    				ANS+=2;
    				ans*=size*(size-1LL)/2LL;
    			}
    			if(CUT==1){
    				ANS+=1;
    				ans*=size;
    			}
    		}
    	}
    	cout<<"Case "<<T<<": "<<ANS<<" "<<ans<<"\n";
    }
    return 0;
}

标签:一个点,点双,int,题解,ll,割点,HNOI2012,low,P3225
From: https://www.cnblogs.com/cmd-pig/p/17363175.html

相关文章

  • Codeforces Round 868 (Div. 2) A-E题解
    比赛地址这把真不在状态,麻了,看来还得再练A.A-characteristic题意:给出n和k,要求构造只含1和-1数组a,存在k对(i,j)(i≠j),有a[i]*a[j]=1Solution令构造的数组有x个1和y个-1,那么其对于答案的贡献有\[x*(x-1)/2+y*(y-1)/2\]又因为有x+y=n,所以可以转化成关于x的一元二次方程化简后......
  • COMPSCI 589 问题解答
    COMPSCI589Homework4-Spring2023DueMay6,2023,11:55pmEasternTime1InstructionsThishomeworkassignmentconsistsofaprogrammingportion.Whileyoumaydiscussproblemswithyourpeers,youmustanswerthequestionsonyourownandimplementall......
  • P4681 [THUSC2015]平方运算 题解
    题面链接简要题意给定一个序列,区间.map([](intx){x=x*x%p;});,区间求和。p给定,为小质数。\(N,M\le10^5\)。题解而把一个数看作一个点,向其平方取模连一条边,则最终必然构成一个基环森林,注意到\(P\)很小,每个数经过\(11\)次迭代之后就会进入环中。对于一个区间,如......
  • “makefile:425: *** 遗漏分隔符 。 停止。”问题解决
    在终端下输入make时出现“makefile:2:***遗漏分隔符。停止。”问题,原因是在编写makefile文件时:3:3.c        gcc-o33.cgcc前的是tab分隔符,不能用空格,否则会出现“makefile:2:***遗漏分隔符。停止。”提示。。。make中规定每一Shell命令之前的开头必须使用<t......
  • 题解(开始学知识点
    D.FrogTraveler1900dpgq!https://codeforces.com/contest/1602/problem/D题解:我们可以通过类似bfs的过程找到每个点的能到达的所需步数最小的点,完成更新,但每个点能被哪些点到达很难判断,故我们反过来考虑,如果我们能得到从n->0的最短跳跃次数,亦得解,而每个点下一步能到达的点容......
  • P1345 [USACO5.4]奶牛的电信Telecowmunication 题解
    一、题目描述:n个点,m条边,给定起点s和终点t,求最少删去几个点后,s和t不连通。注意,s和t不能删掉。1<=n<=100,1<=m<=600; 二、解题思路:刚刚学了最大费用流,知道最大流等于最小割。但此题割的不是边,是点。我们需要将将割点转化为割边。把一个点切成两半......
  • 【题解】P3185 [HNOI2007]分裂游戏
    P3185[HNOI2007]分裂游戏题目描述聪聪和睿睿最近迷上了一款叫做分裂的游戏。该游戏的规则是:共有\(n\)个瓶子,标号为\(0,1,\ldots,n-1\),第\(i\)个瓶子中装有\(p_i\)颗巧克力豆,两个人轮流取豆子,每一轮每人选择\(3\)个瓶子,标号为\(i,j,k\),并要保证\(i\ltj,j......
  • 【题解】P4363 [九省联考 2018] 一双木棋 chess
    原题链接题目描述菲菲和牛牛在一块\(n\)行\(m\)列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋......
  • BUAACTF2023 Writeup题解 by Joooook
    BUAACTF2023WriteupbyJoooook目录MiscWhichElementchatgptzhuzhuzhuzhu'srevengeScreenshotcarzymazeMCCryptoBlockCipherMathKeyExchangeWebmotaReverseoneQuiz'srevenge*SnakeMinesweepobfu可以从队名猜一下博主是哪里人(nooffline......
  • 【题解】XX Open Cup, GP of Moscow
    //createdon23.03.26目录A.AliceandBobB.BracketsC.CirclesD.DejaVuE.EasiestSumF.FunnySalesmanG.GraphColoringH.HiddenGraphI.InsectsJ.JoiningPointsA.AliceandBob对于链上的情况,异色点是一定不会选择走进同色段的(长度不小于\(2\)),因为一定不优。......