机房测试2:home(tarjan求必经点)

题目:

求一张无向图从1走到N的必经点

n<=2e5   m<=4e5

分析:

必经点意为:删除后整个图不连通,但不能直接求割点。因为删掉的那个点可以使图不连通,但不能保证1与n不连通。

所以要删的是在1到n路径上的点。也就是说,删掉的点能使1和n隔开。

法1:

tarjan判环的时候从1开始,并维护一个数组siz[v]:表示v这个点在搜索树中的子树里有没有n这个点,每一次回溯的时候将标记回传给u(u是v的father)。

在判割点的条件:low[v]<=dfn[u](u的子树不能到达比u高的点) 再加一个限制:siz[v]==1(v这个子树中有n)

为什么不是siz[u]==1?

可能出现u的非v子树中有n,去掉u后1和n仍相连。

法2:

判环的时候多加这一个条件:dfn[v]<=dfn[n](n比v后遍历到)

画图可知满足题意

#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define ri register int
int siz[N],low[N],nex[N<<2],head[N],to[N<<2],dfn[N],cut[N];
int Ti=0,tot=0,n,m,ans=0;
int read()
{
    int x=0,fl=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) fl=-1; ch=getchar(); }
    while(ch<=‘9‘&&ch>=‘0‘) x=x*10+ch-‘0‘,ch=getchar();
    return x*fl;
}
void add(int a,int b)
{
    to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
    to[++tot]=a; nex[tot]=head[b]; head[b]=tot;
}
void dfs(int u,int fa)
{
    dfn[u]=low[u]=++Ti;
    if(u==n) siz[u]=1;
    bool flagg=0;
    for(ri i=head[u];i;i=nex[i]){
        int v=to[i];
        if(!dfn[v] && v!=fa){
            dfs(v,u);
            low[u]=min(low[u],low[v]);
            siz[u]|=siz[v];
            if(siz[v] && low[v]>=dfn[u]) flagg=1;
            //这里一定是siz[v] 为了保证一定是从v的子树传上来的标记 而不是从u的另一个子树传上来的标记
            //因为这里判u是割点是根据子树v来判断的
            //也就是说 割掉u之后 子树v和其它部分会分裂 而n刚好在子树v中 而不会和1在一个块中
            //还有一种打法:dfn[v]<=dfn[n](也就是说n在v后遍历到)
            //1. n在v的子树中  2.n在u的另一个非v的子树里(因为n一定要提前遍历 dfn才有值 所以正确性可以保证)
        }
        else if(v!=fa) low[u]=min(low[u],dfn[v]);
    }
    if(u!=1 && flagg) ans++,cut[u]=1;
}
int main()
{
    //freopen("home.in","r",stdin);
    //freopen("home.out","w",stdout);
    int T=read();
    while(T--){
        n=read(); m=read();
        while(m--) add(read(),read());
        dfs(1,0);
        printf("%d\n",ans);
        for(ri i=1;i<=n;++i) if(cut[i]) printf("%d ",i);
        printf("\n");
        for(ri i=1;i<=n;++i) dfn[i]=nex[i]=to[i]=head[i]=low[i]=siz[i]=cut[i]=0;
        Ti=0; tot=0; ans=0;
    }
}
/*
1
10 11
1 10
10 6
6 7
7 8
8 5
5 3
3 9
9 4
4 2
6 2
8 7
*/

原文地址:https://www.cnblogs.com/mowanying/p/11620377.html

时间: 2024-10-10 14:35:56

机房测试2:home(tarjan求必经点)的相关文章

CCF 高速公路 tarjan求强连通分量

问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的计划.看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能.如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对. 国王想知道,在大臣们给他的计划中,有多少个便利城市对. 输入

【BZOJ3331】[BeiJing2013]压力 Tarjan求点双

[BZOJ3331][BeiJing2013]压力 Description 如今,路由器和交换机构建起了互联网的骨架.处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量.他们每天都生活在巨大的压力之下. 小强建立了一个模型.这世界上有N个网络设备,他们之间有M个双向的链接.这个世界是连通的.在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备. 一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径.不过,某些数据包无论走什么路径都不可避免的要通过

【最近公共祖先Tarjan】Tarjan求LCA练习

Tarjan求LCA 这是一篇非常好的讲解,靠这个文章搞懂的~ 1 void tarjan(int u) 2 { 3 vis[u]=1; 4 for(int i=0;i<edge[u].size();i++) 5 { 6 int v=edge[u][i]; 7 if(vis[v] == 0) 8 { 9 tarjan(v); 10 p[v]=u; 11 } 12 } 13 for(int i=0;i<qy[u].size();i++) 14 { 15 int v=qy[u][i].v,id=q

【tarjan求割顶】BZOJ2730-[HNOI2012]矿场搭建

[题目大意] 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数. [思路] 可以得出这样的结论: (1)如果一个点是割点,那么在它上面建救援出口是没有意义的 (2)对于出去割点后的连通块,如果它和两个及以上的割点相连,这不需要建救

UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了. 求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u.具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/377642

UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u],则边(u,v)为桥(封死在子树内),不操作. 求割点时,枚举所有与当前点u相连的点v: 1.是重边: 忽略 2.是树边: Tarjan(v),更新low[u]=min(low[u],low[v]); 子树个数cnt+1.如果low[v] >= dfn[u],说明是割点,割点数+1 3.是回边: 更新lo

HDU 4738 Caocao&#39;s Bridges tarjan求桥

Caocao's Bridges Problem 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 at water battles, so he came up with another idea. He built many islands in the Chan

Tarjan求桥和割点

//Tarjan 求桥和割点 Tarjan(u,fa) { DFN[u]=LoW[u]=++time; Cu=grey; for each e=(u,v) { Tarjan(v,u); if(Cv=white) { low[u]=min(low[u],low[v]); }else { low[u]=min(low[u],DFN[v]); } } }

tarjan求割边割点

tarjan求割边割点 内容及代码来自http://m.blog.csdn.net/article/details?id=51984469 割边:在连通图中,删除了连通图的某条边后,图不再连通.这样的边被称为割边,也叫做桥.割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通.这样的点被称为割点.DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树. 树边:在搜索树中的蓝色线所示,可理解为在DFS过程中访问未访问节点时所经过的边,也称为父子边