• 题解 CF999E 【Reachability from the Capital】


    (quad)前置芝士:Tarjan缩点,建议做做模板题(P3387 【模板】缩点)

    [ ext{关于题意} ]

    (quad)给定一个有向图,求要使一个点 (t) 能够到达其他所有点还需加多少边?

    (quad)因为在一个强连通分量中,每个点都可以到达其他所有点,所以考虑缩点,将一个强连通分量中所有点看做一个点,再做其他操作。

    (quad)缩点之后图就变成了(DAG)(有向无环图),然后考虑每一个点的入度情况(缩点后),因为点 (t) 要能到达其他每一个点,所以除了点 (t) 所在的强连通分量之外,其他所有点的入度必须大于(0),通过找规律就可以发现答案就是缩点后入度为 (0) 且不是点 (t) 所在的强连通分量的点的数量。(因为即使t所在的强连通分量入度为0,也不需要连边)

    (quad)如果还不能理解就看代码吧,注释都在代码里。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<algorithm>
    #define int long long
    #define re register int
    #define il inline
    #define next ne
    using namespace std;
    il int read()					     //快速读入
    {
    	int x=0,f=1;char ch=getchar();
    	while(isdigit(ch)==0&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch-'0'),ch=getchar();
    	return x*f;
    }
    const int N=5e3+5;
    int n,m,dfn[N],low[N],c[N],f[N*2],s[N],l[N]
    int next[N*2],go[N*2],head[N],tot,cnt,ans,t;
    il void Add(int x,int y)  			     //链式前向星存图,记录每条边的端点u,v,之后要计算每个点的入度
    {
    	next[++tot]=head[x];
    	head[x]=tot;
    	f[tot]=x;
    	go[tot]=y;
    }
    stack<int>q;					     //个人喜欢用stack栈,不用数组模拟栈
    il void Tarjan(int x)				     //Tarjan缩点板子
    {
    	dfn[x]=low[x]=++cnt;
    	q.push(x);
    	for(re i=head[x];i;i=next[i])
    	{
    		int y=go[i];
    		if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);
    		else if(!c[y])low[x]=min(low[x],dfn[y]);
    	}
    	if(dfn[x]==low[x])
    	{
    		c[x]=++c[0];
    		s[c[0]]=1;
    		while(q.top()!=x)
    		{
    			c[q.top()]=c[0];
    			s[c[0]]++;
    			q.pop();
    		}
    		q.pop();
    	}
    }
    signed main()
    {
    	n=read();m=read();t=read();
    	tot=cnt=0;
    	for(re i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		Add(x,y);
    	}
    	for(re i=1;i<=n;i++)
    	if(!dfn[i])Tarjan(i);
    	if(c[0]==1){printf("0
    ");return 0;}	//如果只有一个强连通分量,不需要加边
    	for(re i=1;i<=m;i++)
    	{
    		int x=c[f[i]],y=c[go[i]];
    		if(x!=y)l[y]++; 		//记录每个点的入度(缩点后)
    	}
    	for(re i=1;i<=c[0];i++)			//条件1:入度为0   条件2:不是t所在的强连通分量
    	if(!l[i]&&i!=c[t])ans++;		//统计答案
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    (quad)如果觉得我写得好的,不妨点个赞呗

  • 相关阅读:
    docker制作容器(待更新)
    docker 容器连接宿主机mysql问题
    发布linux应用程序(待更新)
    docker 常用命令 (日常更新)
    多线程还是多进程的选择及区别(转)
    关于C++ const 的全面总结《转》
    JS闭包详解
    JS基础——js动画
    JS基础——innerHTML、CSS-DOM
    JS基础——DOM(一)
  • 原文地址:https://www.cnblogs.com/FarkasW/p/13916608.html
Copyright © 2020-2023  润新知