cogs 1001. [WZOI2011 S3] 消息传递 Tarjan

1001. [WZOI2011 S3] 消息传递

★★   输入文件:messagew.in   输出文件:messagew.out   简单对比
时间限制:1 s   内存限制:128 MB

 

 

 

 




 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 




 

 

 

 

 

 

 

这一道题其实还是比较简单的 就是一个Tarjan而已
那么应该怎么进行处理呢??只要  当前点所在的强连通分量的大小>1 就相当于 这个点传出去以后 还能有人再给他传回来!else  就是他自己一个人 肯定不行啦

至于那个认识关系可能会重复。。。我一开始也没有想到怎样处理 就闭着眼交了上去 居然A了 后来想明白了(还是板子高明啊)快看快看:

那个第67行看到没  就是如果to点已经在栈中了  就把当前点的low 和 to点的dfn取一个较小的值 直接就返回了 不会出bug了

 

(<<本人心声:清华orz的板子就是厉害!赞一个)

下面来贴出简洁清晰(自认为)的代码吧

#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define maxn 100005
using namespace std;
int n,m;
vector<int> v[maxn];
int dfn[maxn],low[maxn],size[maxn],scc_cnt,st[maxn],cnt,tim,belong[maxn];
bool bein[maxn];
void Tarjan(int rt)
{
    dfn[rt]=low[rt]=++tim;//时间戳++ 初始化dfn和low相等
    st[++cnt]=rt;//该点入栈
    bein[rt]=true; //标记是否在栈中的数组
    for(int i=0;i<v[rt].size();i++)
    {
        int to=v[rt][i];
        if(!dfn[to]) 
            Tarjan(to),low[rt]=min(low[rt],low[to]);
        else if(bein[to])
            low[rt]=min(low[rt],dfn[to]);
    }
    if(dfn[rt]==low[rt])
    {
        scc_cnt++;//统计强连通分量 
        int k;
        do{
            k=st[cnt];
            cnt--;
            belong[k]=scc_cnt;
            bein[k]=false;
            size[scc_cnt]++;
        }while(k^rt);//^ 在这里就相当于!=        do while  是先跑一遍再判断    
    }
}
int main()
{
    freopen("messagew.in","r",stdin);
    freopen("messagew.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        v[x].push_back(y);//这里要注意是一条单项边啊 
    }    
    for(int i=1;i<=n;i++)
        if(!dfn[i])//如果未访问 
            Tarjan(i);
    for(int i=1;i<=n;i++)
    {
        if(size[belong[i]]>1)
            puts("T");
        else
            puts("F");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Tidoblogs/p/11329587.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值