2017.7.18. Tarjan(缩点)

版权声明:本文为博主原创文章,未经博主允许你想转还是转吧总之我这点东西还有版权这说法吗呵呵呵呵…… https://blog.csdn.net/AVALON_X/article/details/75271296

Tarjan(缩点)

适用题型:有关强连通分量的图
1.询问各点是否在同一强连通分量内
2.询问强连通分量出度
3.询问强连通分量入度

样题:

题目描述
每一头牛的愿望就是变成一头最受欢迎的牛。现在有 N 头牛,给你 M 对整数(A,B),表示牛A认为牛B受欢迎。这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

输入格式
第一行两个数 N,M 。
接下来 M 行,每行两个数 A,B,意思是 A 认为 B 是受欢迎的(给出的信息有可能重复,即有可能出现多个 A,B)

输出格式
输出一个整数,即有多少头牛被所有的牛认为是受欢迎的。如果没有满足这种条件的情况,输出“0”。

样例数据:
输入  输出
3 3 1
1 2
2 1
2 3

备注
【样例说明】
只有牛 3 是受到所有牛欢迎的。

【数据范围】
10% 的数据:N≤20;M≤50
30% 的数据:N≤1000;M≤20000
70% 的数据:N≤5000;M≤50000
100% 的数据:N≤10000;M≤50000

std.cpp:

//std answer of Tarjan
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;

#define MAXE 100050
#define MAXV 500050

using namespace std;

struct edge
{
    int u,v,next;
}edges[MAXE];

int n,m;
int head[MAXV],nCount=0;
int low[MAXV],dfn[MAXV],belong[MAXV],stack[MAXV],top=0;
int cnt=0,tot=0;               //tot=强连通分量个数
int num[MAXV],outDegree[MAXV],inDegree[MAXV]; //num[i]=第i号强连通分量里的点个数,outDegree=出度,inDegree=入度
bool visit[MAXV];

void AddEdge(int U,int V)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

void tarjan(int u) //tarjan缩点
{
    low[u]=dfn[u]=++cnt;
    stack[++top]=u;
    visit[u]=true;
    for(int p=head[u];p!=-1;p=edges[p].next)
    {
        int v=edges[p].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(visit[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        tot++;
        int v=-1;
        while(u!=v)
        {
            v=stack[top--];
            belong[v]=tot;
            num[tot]++;
            visit[v]=false;
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        AddEdge(u,v);
    }

    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);

    for(int i=1;i<=m;i++)
        if(belong[edges[i].u]!=belong[edges[i].v])
        {
            inDegree[belong[edges[i].v]]++;
            outDegree[belong[edges[i].u]]++;
        }

    int res=0,ans;        //res=出度为0的点的个数,ans=出度为0的强连通分量编号
    for(int i=1;i<=tot;i++)
        if(outDegree[i]==0)
        {
            res++;
            ans=i;
        }

    if(res==1) printf("%d\n",num[ans]);
    else printf("0\n");
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页