LA4287--tarjan

题目大意:

在数学中,我们常常需要完成若干个命题的等价性证明。比如,有4个命题a,b,c,d,我们证明a↔b,然后b↔c,最后c↔d。注意每次证明都是双向的,因此一共完成了6次推导。另一种方法是a→b,然后b→c,接着c→d,最后d→a,只需4次。现在你的任务是证明n个命题全部等价,且你的朋友已经为你做出了m次推导(已知每次推导的内容),你至少还需要做几次推导才能完成整个证明?

先tarjan一遍求出强连通分量,缩点,统计每个点的出入度。设有a个节点入读为0,b个节点出度为0,则答案就是max(a,b)。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<string.h>
using namespace std;
vector<int>g[20001];
int n,m,t,i,j,x,y,dfn[20001],dfs_clock,low[20001],in0[20001],out0[20001],c[20001],a,b,l,f[20001],cnt;
void dfs(int u){
    dfn[u]=low[u]=++dfs_clock;
    c[++l]=u;
    for(int i=0;i<g[u].size();++i)
    if(!dfn[g[u][i]]){
        dfs(g[u][i]);
        low[u]=min(low[u],low[g[u][i]]);
    }else if(!f[g[u][i]])low[u]=min(low[u],dfn[g[u][i]]);
    if(low[u]==dfn[u]){
        cnt++;
        while(c[l]!=u)f[c[l--]]=cnt;
        f[c[l--]]=cnt;
    }
}
int main()
{
    scanf("%d",&t);
    for(int u=0;u<t;++u){
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;++i)g[i].clear();
        for(i=1;i<=m;++i){
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
        }
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(in0,0,sizeof(in0));
        memset(out0,0,sizeof(out0));
        memset(f,0,sizeof(f));
        memset(c,0,sizeof(c));
        a=0;b=0;l=0;cnt=0;dfs_clock=0;
        for(i=1;i<=n;++i)if(!dfn[i])dfs(i);
        for(i=1;i<=n;++i)
        for(j=0;j<g[i].size();++j)
        if(f[g[i][j]]!=f[i]){
            in0[f[g[i][j]]]++;
            out0[f[i]]++;
        }
        for(i=1;i<=cnt;++i){
            if(!in0[i])a++;
            if(!out0[i])b++;
        }
        if(cnt==1)printf("0\n");else printf("%d\n",max(a,b));
    }
    return 0;
}

LA4287

时间: 2024-08-05 07:38:18

LA4287--tarjan的相关文章

有向图强连通分支的Tarjan算法讲解 + HDU 1269 连通图 Tarjan 结题报告

题目很简单就拿着这道题简单说说 有向图强连通分支的Tarjan算法 有向图强连通分支的Tarjan算法伪代码如下:void Tarjan(u) {dfn[u]=low[u]=++index//进行DFS,每发现一个新的点就对这个点打上时间戳,所以先找到的点时间戳越早,dfn[U]表示最早发现u的时间,low[u]表示u能到达的最早的时间戳.stack.push(u)//将U压入栈中for each (u, v) in E {if (v is not visted)//如果V点没有经历过DFS,则

【LCA/tarjan】POJ1470-Closest Common Ancestors

[题意] 给出一棵树和多组查询,求以每个节点为LCA的查询数有多少? [错误点] ①读入的时候,注意它的空格是随意的呀!一开始不知道怎么弄,后来看了DISCUSS区大神的话: 询问部分输入: scanf("%d",&m); for(int i=0;i<m;i++){ scanf(" (%d %d)",&a,&b); } 注意scanf(" 这里有一个空格 ②多组数据啊!注意这句话:The input file contents

tarjan强连通图分量

[有向图强连通分量] 有向图强连通分量的Tarjan算法 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. [Tarjan算法] Tarjan算法是基于对图深

POJ 1236 tarjan

Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19613   Accepted: 7725 Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a li

【最近公共祖先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

UVa 12587 Reduce the Maintenance Cost(Tarjan + 二分 + DFS)

题意:n个城市(n <= 10000), 有m条边(m <= 40000),每一个城市有一个维护费用Cost(i),除此之外,每条边的维修费用为去掉该边后不能通信的城市对数与边权的积.这个费用要加到这条边的两端城市的某一个,问你全部城市的最大费用的最小值.. 思路:首先边的费用能够通过Tarjan求桥之后求得(利用桥的性质),然后就是二分答案了!对于每一个点,假设有个儿子不能维护.那么不可行,否则.试着让儿子去维护边权,假设不可行,仅仅能让父亲承担. #include <iostream

hdu 2586(Tarjan 离线算法)

How far away ?                                                                             Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                                                            

【转】BYV--有向图强连通分量的Tarjan算法

转自beyond the void 的博客: https://www.byvoid.com/zhs/blog/scc-tarjan 注:红色为标注部分 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶

【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 的时间内求出一个图的所有强联通分量. 表示进入结点 的时间 表示从 所能追溯到的栈中点的最早时间 如果某个点 已经在栈中则更新  否则对 进行回溯,并在回溯后更新  #include<iostream> #include<cstdlib> #include<cstdio>

(转载)LCA问题的Tarjan算法

转载自:Click Here LCA问题(Lowest Common Ancestors,最近公共祖先问题),是指给定一棵有根树T,给出若干个查询LCA(u, v)(通常查询数量较大),每次求树T中两个顶点u和v的最近公共祖先,即找一个节点,同时是u和v的祖先,并且深度尽可能大(尽可能远离树根).LCA问题有很多解法:线段树.Tarjan算法.跳表.RMQ与LCA互相转化等.本文主要讲解Tarjan算法的原理及详细实现. 一 LCA问题 LCA问题的一般形式:给定一棵有根树,给出若干个查询,每个