10.28机房小测T2-tarjan判断必经点
来源:互联网 发布:linux sftp 端口 编辑:程序博客网 时间:2024/06/06 04:52
说在前面
没什么好说的=w=(但是要保持格式)
题目
(原样例实在是太水了,我自己出了几组,在程序末尾)
解法
一个很经典的模型:”一张无向图从1走到N的必经点”
考试的时候写出来的程序在逻辑上有点问题,不过me的代码自带容错性,卡不掉的hhhhhh。不过还是决定把这个问题记录下来,以后方便复习。
可以发现,必经点一定是1到N路径上的某一个点(路径上每个点只能经过一次,不能1->u->v->u->N),me称之为路径点。那么只需要将所有这样的点先用一边dfs标记出来,然后再跑一遍tarjan求割点就好了。
相当于是要把图上的”枝丫点”给撇开不管,找剩下的图中的割点。
然而这样的”路径点”并不能用像下面这样的dfs去预处理:
bool acc[100005] ;void dfs_acc( int u , int f ){ if( u == N ) acc[u] = true ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; if( v == f ) continue ; dfs_acc( v , u ) ; acc[u] |= acc[v] ; }}
这个dfs的思路很简单,却存在漏洞。
因为dfs是有先后顺序的。比如上面这个图,dfs顺序可能如下:
1->5->8->9->6->1->return,如果在9号节点先进入的是6号节点,那么6号节点就无法被标记为”路径点”。因此是无法先用一边dfs预处理的。
正确的做法是在tarjan的时候,无论点是不是路径点,都进去dfs一遍。如果在某一个u->v的时候有lowv ≥ dfn[u],并且v可以到达N点,u才是必经点。正确性是显然的,如果是v导致了u被判为割点,并且v还能到N点,那么说明N一定在v的子树内。这种情况下,1点必须经过u点才能走到N,可以感性理解一下。
因此严谨的逻辑是:先判断割点,再看导致该点被判为割点的点是否是”路径点”,如果是,那么该点就是割点。
而不严谨的逻辑是:先判断该点是路径点,再跑tarjan求割点。(其实这个逻辑是对的,但是实现过程会出错)
自带大常数的代码
#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;int T , N , M , tp , head[200005] , cnt ;struct Path{ int pre , to ;}p[4*200005] ;void In( int t1 , int t2 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ;}inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}bool iscut[200005] , acc[200005] ;int dfn[200005] , dfs_c ;int dfs( int u , int f ){ int lowu = dfn[u] = ++dfs_c ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; if( v == f ) continue ; if( !dfn[v] ){ int lowv = dfs( v , u ) ; lowu = min( lowu , lowv ) ; if( lowv >= dfn[u] && acc[v] ) iscut[u] = true ; } else lowu = min( dfn[v] , lowu ) ; acc[u] |= acc[v] ; } return lowu ;}void solve(){ acc[N] = true ; dfs( 1 , 0 ) ; for( int i = 2 ; i < N ; i ++ ) if( iscut[i] ) cnt ++ ; printf( "%d\n" , cnt ) ; for( int i = 2 ; i < N ; i ++ ) if( iscut[i] ) printf( "%d " , i ) ; printf( "\n" ) ;}void clear(){ dfs_c = tp = cnt = 0 ; memset( head , 0 , sizeof( head ) ) ; memset( dfn , 0 , sizeof( dfn ) ) ; memset( acc , false , sizeof( acc ) ) ; memset( iscut , false , sizeof( iscut ) ) ;}int main(){ freopen( "home.in" , "r" , stdin ) ; freopen( "home.out", "w" , stdout) ; T=read(); while( T -- ){ clear() ; N=read(),M=read(); for( int i = 1 , u , v ; i <= M ; i ++ ){ u=read(),v=read(); In( u , v ) ; In( v , u ) ; } solve() ; } return 0 ;}/*54 31 22 33 45 51 22 33 44 54 120 221 22 32 43 53 64 74 85 99 108 1111 125 135 146 147 158 158 1613 1714 1815 1816 1918 205 51 22 33 51 44 55 51 22 33 44 54 1*/
- 10.28机房小测T2-tarjan判断必经点
- 一道好题:机房小测-Tarjan判断必经点
- 割点判断(tarjan)
- 2017.10.28 Tarjan求无向图必经点 解题报告
- [题解] CodeVS 2370 小机房的树(LCA Tarjan)
- 【tarjan缩点+小拓展】【POJ-2186】
- poj 2942 染色判断奇数+tarjan求点连通分量
- 图的连通性强弱判断(tarjan+缩点)
- LCA(最近公共祖先 Tarjan) CodeVs-2370-小机房的树
- 关于支配点(必经过点)的人生经验
- poj1904 tarjan缩点
- poj2117 tarjan()+割点
- HDU3836 Tarjan缩点
- HDU3836(tarjan+缩点)
- 1827 tarjan+缩点
- tarjan+缩点
- tarjan + 缩点
- Tarjan缩点
- kafka 安装与配置
- 写博客
- PAT 1025
- Linux命令(压缩,解压rar)
- [新手编程训练项目]006——C语言文件夹文本文件关键词检测
- 10.28机房小测T2-tarjan判断必经点
- 阅文集团重现盛大往事,多家子公司CEO离职!
- 滴滴又获73亿美元融资 成为全球第三大独角兽
- 比特币开挂疯涨 炮灰明显不够用了
- IEEE院士Ming C. Lin:VR中音频渲染模拟为何这么难?
- 692. Top K Frequent Words
- Unity 2D角色控制脚本C#直接上代码
- 正则表达式【语法、说明、表达式实例】
- 【OpenGL】窗口,视口,裁剪区