题解——home(必经路tarjan)

题解——home(必经路tarjan)

校内胡策题9月29日,ssw02估分150,实际得分9,这道题估分100,实际爆零

题面搬运

题面讲述了一个ssw02(假)在学校逃课,老师来抓ssw02的故事。

输入:T组数据,每组数据一个图
输出:T组数据,每组输出一定可以抓到ssw02的点的个数和点。

思路

首先我们想到,这些可以抓到ssw02的点一定是整个图的割点(如果你这没想到,可以去重新学习一下割点)。

然后我们发现,啊,不对,有的割点好像走都不会走。然后我们加上以下代码,去找了一下那些点走过。

void  dfs( int u , int fa ){
   anc[ u ] = fa , vis[ u ] = true ;
   for( register int i = head[ u ] ; i ; i = nex[ i ] ){
       if( to[ i ] == fa )continue ;
       if( vis[ to[ i ] ] )continue ;
       dfs( to[ i ] , u ) ;
   }
}
int now = N ; vis[ now ] = true ;//main中
while( now != 1 )vis[ now ] = true , now = anc[ now ] ;

然后,秒切样例,一交,100少了个0,只有10。

我们来想想为什么?

给出下面一组数据:

10 11
1 6
6 10
10 5
5 8
8 9
9 3
3 7
7 2
2 4
5 6
7 7

仔细想想,发现我们可能先遍历5号点,再遍历6号点,然后5,6都通过了check。

本质原因错在哪? --我们并没有保证 5 , 6 不在一个连通块内。

然后Tarjan神仙又出现了,你没看错,tarjan在处理割点时还可以处理满足固定路径上点的不连通问题。

我们这次先跑dfs得出一条简单路径,再跑tarjan,并且在tarjan判断割点上加上如下代码

if( u != root || flag > 1 )cut[ u ] = 1 ;

这样我们发现,会被之前已在搜索树上的点更新的目标点并不会被判断为必经路的割点(很显然割掉这个点后,目标点还和搜索树相连)

御坂20001号( SXK )还有这样的理解,供大家参考

然后没了。注意题目给的范围有坑。M>=2*N

代码

#include<bits/stdc++.h>
using namespace std;
const  int  MAXN = 400010  ;
int  head[ MAXN ] , to[ MAXN*2 ] , nex[ MAXN*2 ] ;
int  dfn[ MAXN ] , low[ MAXN ] , anc[ MAXN ];
int  T , N , M , tot = 1 , num , root ;
bool vis[ MAXN ] , cut[ MAXN ] ;
inline int read(){
    int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ;
    while( g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
void  add( int x , int  y ){
    to[ ++tot ] = y , nex[ tot ] = head[ x ] , head[ x ] = tot ;
}
void  tarjan( int u ){
    dfn[ u ] = low[ u ] = ++num ;
    int  flag = 0 ;
    for( register int i = head[ u ] ; i ; i = nex[ i ] ){
        int y = to[ i ] ;
        if( !dfn[ y ] ){
            tarjan( y ) ;
            low[ u ] = min( low[ u ] , low[ y ] ) ;
            if( low[ y ] >= dfn[ u ] && vis[ y ] ){
                flag++ ;
                if( u != root || flag > 1 )cut[ u ] = 1 ;
            }
        }
        else low[ u ] = min( low[ u ] , dfn[ y ] ) ;
    }
}
void  dfs( int u , int fa ){
    anc[ u ] = fa , vis[ u ] = true ;
    for( register int i = head[ u ] ; i ; i = nex[ i ] ){
        if( to[ i ] == fa )continue ;
        if( vis[ to[ i ] ] )continue ;
        dfs( to[ i ] , u ) ;
    }
}
void  work(){
    N  = read() , M = read() ;
    for( register int i = 1 ; i <= M ; i++ ){
        int  m1 = read() , m2 = read() ;
        if( m1 == m2 )continue ;
        add( m1 , m2 ) , add( m2 , m1 ) ;
    }
    dfs( 1 , 1 ) ; for( register int i = 1 ; i <= N ; ++i )vis[ i ] = false ;
    int now = N ; vis[ now ] = true ;
    while( now != 1 )vis[ now ] = true , now = anc[ now ] ;
    for( register int i = 1 ; i <= N ; i++ )
        if( !dfn[ i ] ){
            root = i ; tarjan( i );
        }
    int  ans = 0 ;
    for( register int i = 2 ; i < N ; i++ )
        if( cut[ i ] )ans++ ;
    printf("%d\n",ans);
    for( register int i = 2 ; i < N ; i++ )
        if( cut[ i ]  ){
            printf("%d ",i);cut[ i ] = 0 ;
        }
    printf("\n") ;
    for( register int i = 1 ; i <= N ; ++i )
        vis[ i ] = dfn[ i ] = low[ i ] = head[ i ] = anc[ i ] = 0 ;
    tot = 1 , num = 0 ;
}
int  main()
{
    freopen("home.in","r",stdin);
    freopen("home.out","w",stdout);
    T = read() ;
    while( T-- )work() ;
    return  0 ;
}
/*
1
5 5
1 2
2 3
3 4
4 5
4 1
*/

原文地址:https://www.cnblogs.com/ssw02/p/11623321.html

时间: 2024-11-11 11:09:18

题解——home(必经路tarjan)的相关文章

定制化成企业IT构建必经路

我们构建的IT系统的复杂性以及我们期望它完成的任务的复杂性,这种调整计算系统的方法不只是一个选择,而是一个必要. 并不是所有的企业计算任务都是相同的,计算系统也同样如此.只有执行特定工作的系统或者具有足够灵活性来适应各种工作的系统才能最好的满足企业的需求,也就是“工作负载优化系统”. 考虑一些现实世界的情景:在某工厂,管理资源规划的应用程序需要不同的计算能力来分析移动手机用户间的人力资源流动率,并向他们实时发送新的offer.但实际上,基于web的社交网络工具与会计程序完全不同,而监控电网使用模

hdu 4738 Caocao&#39;s Bridges tarjan

Caocao's Bridges Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4738 Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. Caocao's army still was not good

hihoCoder #1067 : 最近公共祖先&#183;二 [ 离线LCA tarjan ]

传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是

UOJ #146. 【NOIP2015】信息传递 连通分量 tarjan模板题

http://uoj.ac/problem/146 题解:强连通分量 tarjan模板题.同时试了一下codeblock #include<bits/stdc++.h> using namespace std; const int maxn=2e5+5; vector<int> E[maxn]; int dfn[maxn],low[maxn],tot,n,ans=maxn,vis[maxn]; stack<int> S; void tarjan(int x){ low[

2019年7月训练(壹)

2019-07-25 luogu P3627 [APIO2009]抢掠计划 卡了三个小时,看了题解才作出来的(菜) 前驱知识: 壹~邻接表存储/遍历 贰~SPFA跑最长路(<改>就行了) 叄~Tarjan缩点 壹.邻接表储存 两个,add存无边权,未缩点:build有边权,已缩点. void add(int u,int v) { cnt++; e[cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } void build(int u,int v,int

图论之点双&amp;边双

说人话: 边双联通: a到b的路径上无必经边 点双联通: a到b的路径上除了a,b没有必经点 tarjan求点双联通: 代码(补图) 割点: 桥: 求点双:强制dfs时不越过割点,即可求出一个块 求边双:dfs时不越过桥 不是割点:减少2n-1 是割点:减少sigmai的大小*其他所有子树的大小 tarjan求桥,然后缩点,会形成一棵树.把树的所有叶子连起来用的边数就是答案 判断: 当且仅当无向图上不含奇环的时候就是二分图 增广路特点:非匹配边比匹配边多一条 寻找增广路:dfs 咕咕咕~ 网络流

bzoj 4408: [Fjoi 2016]神秘数

额,一开始突然想到了如果能表示出连续的二进制位,就可以构造出连续的数了..然后想了一下,不可做2333 于是又走上了扒题解的不归路.. 貌似题解就是推广一下?? 如果能表示出[l,r]那么新加入一个数a,那么可以得到一个新的区间是[l+a,r+a],然后和 [l,r]and[l+a,r+a](and表示取并集)就是现在能表示的区间. 现在我们希望 [l,r]and[l+a,r+a]==[l,r+a] ,这样的话考虑a的加入顺序,显然是应该从小到大的. 而且,在[l,r]and[l+a,r+a]=

梦旅人-生命的苍凉和绚丽 是自己的选择

原来那天的阳光 “我看过沙漠下暴雨 看过大海亲吻鲨鱼 看过黄昏追逐黎明 没看过你我知道美丽会老去 生命之外还有生命 我知道风里有诗句 不知道你” 宁静的夜里,月色如水,怅然回首,往事如风,记忆如尘. 岁月匆匆流过,沉淀的记忆,漂浮在心头. 抹不去的回忆,只能在文字中寻找缄默的力量. 走到今天,远方的路依不再迷茫,在经历了林林总总之后,我发现我的未来在迷离中渐渐清晰起来. 或许,今天我还是会在疲倦中感叹“行路难,行路难,多歧路,今安在?” 可能,迷茫是我们的必经路,人生,如果没有在乌云下抱怨过,也

【BZOJ】1529 [POI2005]ska Piggy banks

[算法](强连通分量)并查集 [题解] 1.用tarjan计算强连通分量并缩点,在新图中找入度为0的点的个数就是答案. 但是,会爆内存(题目内存限制64MB). 2.用并查集,最后从1到n统计fa[i]==i的数量即是答案. (tarjan) #include<cstdio> #include<algorithm> using namespace std; const int maxn=1000010; struct edge{int u,v,from;}e[maxn]; int