Going from u to v or from v to u? POJ - 2762 是否为单向连通图

19 篇文章 0 订阅
19 篇文章 0 订阅

判断单向连通图 tarjan

题意
给你一个有向图,问任意两点u,v 是否总存在V(u,v) 或 V(v,u)
思路
用tarjan算法将强联通分量缩点
判断生成树(不成树肯定错)是否退化成链
随便深搜一下最长链就好
Ps:这题数据水了
hack数据:
1
4 4
1 2
1 3
2 4
3 4
代码

/*
 * Author       :  Echo
 * Email        :  1666424499@qq.com  
 * Description  :   
 * Created Time :  2017/10/15 17:54:39
 * Last Modify  :  2017/10/16 17:05:15
 * File Name    :  write.cpp
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>

using namespace std;
const int maxn=1100;
const int maxm=10100;
const int INF=1e9;
struct edge {
    int to,next;
}an[maxm],bn[maxm];
int headan[maxn],headbn[maxn];
int dfn[maxn]; //入栈时间戳
int ins[maxn]; //是否入栈
int low[maxn]; //最早发现时间
int stk[maxn]; //手工栈
int dot[maxn]; //缩点
int out[maxn]; //出度
int ind[maxn]; //入度
int len[maxn]; //成链?
int m=0;//edge 
int cntan,cntbn;
int top;//stack
int cnt;//dot
int n;//point
int tm;//time
void addedge(edge a[],int head[],int &cntm,int u,int v){
    a[++cntm].to=v;
    a[cntm].next=head[u];
    head[u]=cntm;
}
void tarjan(int u){
    dfn[u]=low[u]=++tm;
    stk[++top]=u;
    ins[u]=1;
    for(int i=headan[u];i!=-1;i=an[i].next){
        int v=an[i].to;
        if(dfn[v]==0){
            tarjan(v);
            if(low[u]>low[v]) low[u]=low[v];
        } 
        else if(ins[v]&&low[u]>low[v]){
            low[u]=low[v];
        }
    }
    if(low[u]!=dfn[u]) return;
    int v=stk[top--];
    ins[v]=0;
    dot[v]=++cnt;
    while(u!=v){
        v=stk[top--];
        ins[v]=0;
        dot[v]=cnt;
    }
}
void dfs(int u){
    len[u]=1;
    for(int i=headbn[u];i!=-1;i=bn[i].next){
        int v=bn[i].to;
        if(len[v]==0) dfs(v);
        if(len[v]+1>len[u]) len[u]=len[v]+1;
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        scanf("%d%d",&n,&m);
        top=cnt=tm=0;
        for(int i=0;i<=n;i++){
            len[i]=dfn[i]=ins[i]=out[i]=ind[i]=0;
            headbn[i]=headan[i]=-1;
        }
        cntan=cntbn=0;
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(an,headan,cntan,u,v);
        }
        for(int i=1;i<=n;i++){
            if(dfn[i]) continue; 
            tarjan(i);
        }
        for(int u=1;u<=n;u++){
            for(int i=headan[u];i!=-1;i=an[i].next){
                int v=an[i].to;
                if(dot[u]==dot[v])continue;
                addedge(bn,headbn,cntbn,dot[u],dot[v]);
                out[dot[u]]++;
                ind[dot[v]]++;
            }
        }
        int ans=0;
        for(int i=1;i<=cnt;i++){
            if(len[i]) continue;
            dfs(i);
            if(ans<len[i])ans=len[i];
        }
        if(ans!=cnt){
            printf("No\n");
        }
        else printf("Yes\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值