tarjan 题目汇总(含解析)
下面容许我偷个懒,洛谷上写过的blog我就不来再抄一遍了
- 洛谷P3436 【[POI2006]PRO-Professor Szu】(别称:作死的老教授)
- 洛谷P4306 【[JSOI2010]连通数】
- 洛谷P4303 【[AHOI2006]基因匹配】(额…这篇好像发错了,emmm…没事大家可以选择忽略)
- 洛谷UVA11294 【Wedding】(有点BT了最后我再稍微讲讲吧毕竟这道题是道英文题)
那么我先讲一讲今天晚上的第一道题吧(话说今天晚上好黑教室里还就我一个银_ (:з」∠)_)!
题目如下:
[POI2008]BLO-Blockade
题目描述
There are exactly nn towns in Byteotia.
Some towns are connected by bidirectional roads.
There are no crossroads outside towns, though there may be bridges, tunnels and flyovers. Each pair of towns may be connected by at most one direct road. One can get from any town to any other-directly or indirectly.
Each town has exactly one citizen.
For that reason the citizens suffer from loneliness.
It turns out that each citizen would like to pay a visit to every other citizen (in his host’s hometown), and do it exactly once. So exactly n\cdot (n-1)n⋅(n−1) visits should take place.
That’s right, should.
Unfortunately, a general strike of programmers, who demand an emergency purchase of software, is under way.
As an act of protest, the programmers plan to block one town of Byteotia, preventing entering it, leaving it, and even passing through.
As we speak, they are debating which town to choose so that the consequences are most severe.
Task Write a programme that:
reads the Byteotian road system’s description from the standard input, for each town determines, how many visits could take place if this town were not blocked by programmers, writes out the outcome to the standard output.
给定一张无向图,求每个点被封锁之后有多少个有序点对(x,y)(x!=y,1<=x,y<=n)满足x无法到达y
输入输出格式
(不贴了,反正一堆英文你懂得)
输入输出样例
输入样例#1:
5 5
1 2
2 3
1 3
3 4
4 5
输出样例#1:
8
8
16
14
8
题目分析
话说翻译讲的好模糊啊我看着道题看了半天就是看不出来那个答案是怎么来的。。。
好吧我再好好讲讲:这道题就是说给你n个点和m条无向边,让你分别求:第i个点所连的边都被切掉的时候有多少对点是无法相互到达的(注意1 ,2 和 2 , 1是不同的一对点,也可以理解为最终求出的点对要*2),也就是说第i个点也是要算在无法相互到达的点对之内的。另外注意题目给出的图是个无向连通图。完了我也不想赘述了,题意也就差不多是这样,tarjan缩缩点差不多可以水过去。
此外,本题与割点相关
代码
#include<bits/stdc++.h>
#define M 110000
typedef long long ll;
using namespace std;
inline ll read() //日常读优(最近tarjan一堆大数据搞得我很焦躁什么数据类型都用longlong了)
{
ll x=0; char c=getchar();
while(!isdigit(c)) c=getchar();
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
ll n,m,tim,pat=1;
ll size[M],f[M];
ll dfn[M],low[M];
ll head[M],ans[M];
struct Edge{ int v,next; }e[M*10];
void add(int u,int v) { e[pat].next=head[u]; e[pat].v=v; head[u]=pat++; }
void tarjan(int u) //tarjan(相较模板有改动,因为要求割点。PS:本题和割点也有关)
{
int ape=1,chd=0;
++size[u]; ans[u]+=n-1;
dfn[u]=low[u]=++tim;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v; if(f[u]==v) continue;
if(!dfn[v])
{
f[v]=u; tarjan(v); size[u]+=size[v]; ++chd; low[u]=min(low[u] , low[v]);
if(u!=1 && dfn[u]<=low[v]) ape+=size[v], ans[u]+=(n-ape)*size[v];
//是割点,appear加上该子树的size,ans加上未出现的节点数(n-appear)*(该子树的大小)size
}
else low[u]=min(low[u] , dfn[v]);
}
if(u==1 && chd>=2) //单独判断根节点u是否是割点,是的话就进行累加
for(int i=head[u];i;i=e[i].next) if(f[e[i].v]==u)
for(int j=e[i].next;j;j=e[j].next) if(f[e[j].v]==u)
ans[u]+=size[e[i].v]*size[e[j].v]; //这里是直接子树大小 * 子树大小了
}
int main()
{
n=read(); m=read();
for(int i=1;i<=m;++i) //读边不解释
{ int u=read(),v=read(); add(u,v); add(v,u); }
tarjan(1); //该图本身联通,只需从点1出发即可
for(int i=1;i<=n;++i) //tarjan中已经处理完了答案,直接输出即可
printf("%lld\n",ans[i]<<1);
return 0;
}
分割线来调皮了~_(:з」∠)_
[HNOI2012]矿场搭建
题目描述
煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。
请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。
输入输出格式
输入格式:
输入文件有若干组数据,每组数据的第一行是一个正整数 N(N<=500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T,表示挖 S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。
输出格式:
输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与:之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。
输入输出样例
输入样例#1:
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
输出样例#1:
Case 1: 2 4
Case 2: 4 1
说明
Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);
Case 2 的一组解为(4,5,6,7)。
题目分析
(这道题是道中文题不用解释好开森~_(:з」∠)_)
咳咳。然后这道题同上也是要求割点的。= =||| 懒癌晚期不想说什么了代码里分析
代码
#include<bits/stdc++.h>
#define M 510
typedef long long ll;
using namespace std;
inline ll read() //读优你懂的
{
ll x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
int n,m;
ll tim,pat,top,part,res,ans;
ll dfn[M],low[M];
ll num[M],stk[M];
bool vis[M];
struct Node{ int gd,es;}grp[M]; //强连通分量记录割点数和非割点数你懂的
struct Edge{ int v; Edge *next;}*head[M]; //邻接表存边你懂的(只不过用了指针而已啦)
void add(int u,int v) { Edge *p=new(Edge); p->v=v; p->next=head[u]; head[u]=p; }
void tarjan(int u) //tarjan缩点你懂的
{
dfn[u]=low[u]=++tim;
for(Edge *i=head[u];i;i=i->next)
{
int v=i->v;
if(!dfn[v])
{
tarjan(v); low[u]=min(low[u] , low[v]);
if(dfn[u]<=low[v]) ++num[u]; //子树的数目++(比起模板也就这里变了一下吧)
}
else low[u]=min(low[u] , dfn[v]);
}
}
void dfs(int u) //dfs上再来求强连通分量
{
vis[u]=true; stk[++top]=u;
for(Edge *i=head[u];i;i=i->next)
{
int v=i->v;
if(vis[v]) continue;
dfs(v);
if(low[v]>=dfn[u])
{
++part;
int j=0;
do{
j=stk[top--];
if(num[j]) ++grp[part].gd;
else ++grp[part].es;
}while(j!=u);
++top;
}
}
}
int main()
{
int T=0;
while(true)
{
memset(num , 0 , sizeof(num));
memset(stk , 0 , sizeof(stk));
memset(vis , 0 , sizeof(vis));
memset(dfn , 0 , sizeof(dfn));
memset(low , 0 , sizeof(low));
memset(head, 0 ,sizeof(head));
for(int i=0;i<M;++i)grp[i].gd=grp[i].es=0;
pat=tim=part=top=ans=n=0; res=1;
/* 这些可以放到子函数里那样看起来清楚点 */
m=read();
if(!m) return 0;
while(m--)
{
int u=read(),v=read();
n=max(n , max(u , v)); //题目中没说几个矿场我们就找最大值存下来当矿场数
add(u,v); add(v,u);
}
for(int i=1;i<=n;++i) if(!dfn[i])
{
tarjan(i);
if(num[i]>0) //根节点的有效子树数量要-1(当然这里没有这个if也没事直接减减就行)
--num[i];
}
for(int i=1;i<=n;++i) //这时候再深搜找强连通分量(已排除根节点有效子树数量的干扰)
if(!vis[i]) dfs(i);
for(int i=1;i<=part;++i)
{
if(grp[i].gd>=2) continue; //大于两个割点的就不用建出口了,因为任意一个割点矿场毁了后,
//该强连通分量矿场里的人还可以通过剩下来的割点矿场逃到其他强连通分量矿场里找出口
if(grp[i].gd==1) { ++ans; res*=grp[i].es; }
//只有一个割点就要再建一个出口(方案数*该强连通分量矿场中非割点矿场的数量)
else if(grp[i].gd==0) { ans+=2; res*=(grp[i].es*(grp[i].es-1))/2; }
//没有割点的话说明该强连通分量与外界完全分离了,要建两个出口以防万一(可能建出口的那个矿场会炸)
}
printf("Case %d: %lld %lld\n",++T,ans,res);
}
}
= =||| 怎么说好咧,这个题目自己都还是有点疑问,等会儿再想想。。。
那么接下来我就稍微讲讲【wedding】这道题吧。题意就是给你个n和m,表示有n队夫妇,编号为0~n-1,其中0号夫妇今天办了酒宴,然后这些夫妇中有m对人是不能坐在一列的。(好像说是通奸啥的?)那么这m对人相当于两两排斥,不能同时坐在0号新郎那列(但是可以同时坐在0号新娘那列),并且每对夫妇也不可以坐在同一列(假设3号新郎坐在0号新郎那列,那么3号新娘就只能坐在0号新娘那列,也就是和3号新郎不同的那列),然后的话就是要你求和0号新娘坐在同一列的夫妇的任意一种状况(任意一种状况求出来都能AC,也不知道是数据输入的时候就保证了只有唯一解还是评测的时候是一个一个情况去对的,前者可能性较大)。好了那么这道题讲的也就差不多,其实本质上是一个2-SAT问题,不过是最终的答案变成了无矛盾组的取反而已,我也就不多说了这道题还是有点做的价值滴~~~
OK,这篇专题就结束了,小伙伴们下次见~_(:з」∠)_
ヾ( ̄▽ ̄)Bye~Bye~ (喜欢请点赞不喜欢请评论)
tarjan 题目汇总(含解析)的更多相关文章
- 2016年Web前端面试题目汇总
转载: 2016年Web前端面试题目汇总 以下是收集一些面试中经常会遇到的经典面试题以及自己面试过程中未解决的问题,通过对知识的整理以及经验的总结,重新巩固自身的前端基础知识,如有错误或更好的答案,欢 ...
- 前端面试题目汇总摘录(JS 基础篇)
JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...
- leetcode - 位运算题目汇总(下)
接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...
- Dockerfile 指令汇总及解析
原文地址:http://www.maoyupeng.com/dockerfile-command-introduction.html 什么是Dockerfile Dockerfile是由一系列 ...
- LeetCode 11月第2周题目汇总
开源地址:点击该链接 前言 最近比较忙,这周几乎没有刷题,只刷了6道题~ 题目汇总 0387_first_unique_character_in_a_string类似的题目比较多了,字符串中找出特别的 ...
- All LeetCode Questions List 题目汇总
All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...
- Python—经典练手题目汇总
Python-经典练手题目汇总 # 1.有1020个西瓜,第一天卖掉总数的一半后又多卖出两个,以后每天卖剩下的一半多两# 个,问几天以后能卖完? day=0 xg=1020 for i in rang ...
- 最近集训的图论(思路+实现)题目汇总(内容包含tarjan、分层图、拓扑、差分、奇怪的最短路):
(集训模拟赛2)抢掠计划(tarjan强) 题目:给你n个点,m条边的图,每个点有点权,有一些点是"酒吧"点,终点只能在"酒吧",起点给定,路可以重复经过,但点 ...
- PHP 高级面试115题汇总(含答案)
1.给你四个坐标点,判断它们能不能组成一个矩形,如判断 ([0,0],[0,1],[1,1],[1,0]) 能组成一个矩形.勾股定理,矩形是对角线相等的四边形.只要任意三点不在一条直线上,任选一点,求 ...
随机推荐
- SpringCloud(5)路由网关Spring Cloud Zuul
一个简单的微服务系统如下图: 1.为什么需要Zuul Zuul很容易实现 负载均衡.智能路由 和 熔断器,可以做身份认证和权限认证,可以实现监控,在高流量状态下,对服务进行降级. 2.路由网关 继续前 ...
- python list 中 remove 的骚操作/易错点
在过去的某一天(2019.3.19),有个学弟问了一个关于python list中的一个问题: 比如我们已知一个列表 [3,4,5,6,5,4,3] 我们想删除第一个为3的元素. 我们尝试了如下几种方 ...
- 《React Native 精解与实战》书籍连载「Android 平台与 React Native 混合开发」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
- Linux(Ubuntu)使用日记(七)------终端控制器Terminator安装使用
1.目的 实现分屏效果,如图: 如果使用系统自带的终端,可能会使这种效果: 综上所述,知道我们为什么要安装Terminator了吧. 2.安装过程 Terminator 的安装非常方便,在 Ubunt ...
- Python——Microsoft Office编程
一.Excel 需要安装xlrd和xlwt这两个库 1.打开excel readbook = xlrd.open_workbook(r'\test\canying.xlsx') 2.获取读入的文件 ...
- git仓库构建小记
1.新建 .git 文件夹 约定的文件目录下,新建 .git 文件夹 mkdir test.git 2.初始化服务端仓库 git init --bare test.git 此时进入 test.git ...
- Insert Into select 与 Select Into 哪个更快?
在平常数据库操作的时候,我们有时候会遇到表之间数据复制的情况,可能会用到INSERT INTO SELECT 或者 SELECT INTO : 那么二者语法上有什么区别?性能上又如何呢? 围绕着这两个 ...
- 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查
原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...
- 【并发编程】【JDK源码】J.U.C--AQS (AbstractQueuedSynchronizer)(1/2)
J.U.C实现基础 AQS.非阻塞数据结构和原子变量类(java.util.concurrent.atomic包中的类),concurrent包中的基础类都是使用这种模式来实现的.而concurren ...
- Python网络编程(3)——SocketServer模块与简单并发服务器
主要类型 该模块有四个比较主要的类,其中常用的是 TCPServer 和 UDPServer. 1. TCPServer 2. UDPServer 3. UnixStreamServer,类似于TCP ...