POJ2186(Tarjan缩点)

本文深入探讨了网络架构与数据处理技术的核心概念,包括云计算、人工智能、区块链等领域的最新发展。通过详细解释各种关键技术,如云计算平台、深度学习模型、智能合约和隐私计算,读者可以全面了解这些技术如何推动现代信息技术的进步。文章还讨论了数据安全、文档协作与知识管理等实际应用案例,提供了一系列实用的解决方案。

2186 – Popular Cows

Language:

Popular Cows

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 29300 Accepted: 11850
Description

Every cow’s dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

  • Line 1: Two space-separated integers, N and M

  • Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

  • Line 1: A single integer that is the number of cows who are considered popular by every other cow.
    Sample Input

3 3
1 2
2 1
2 3
Sample Output

1
Hint

Cow 3 is the only cow of high popularity.
Source

USACO 2003 Fall

一只奶牛,之间有互相仰慕的关系,如果A仰慕B,B仰慕C,意味着A也仰慕C,问有多少奶牛被所有奶牛仰慕。仰慕关系是有向的,先进行强连通缩点,缩完点之后形成DAG,如果不完全连通,那么没有答案。否则被所有奶牛仰慕的奶牛,必然是在DAG中出度为0的结点中,并且该结点的强连通分量个数为1。
我的代码里是先跑一遍tarjan,belong数组里面存的是一个点属于哪个连通分量。在这基础上建树也就是上面说的哪个DAG,接下来用上面的那个条件判断一波就可以了。

#include "cstring"
#include "cstdio"
#include "iostream"
using namespace std;
#define V    10005
#define E    50005
struct edge
{
    int to, next;
}Edge[E],newEdge[E];
int head[V], e, n;
int newhead[V];
int indeg[V], outdeg[V]; //点的入度和出度数
int belong[V], low[V], dfn[V], scc, cnt;//dfn[]:遍历到u点的时间; low[]:u点可到达的各点中最小的dfn[v]
int S[V], top;
bool vis[V];//v是否在栈中

int addedge(int u, int v)
{
    Edge[e].to = v;
    Edge[e].next = head[u];
    head[u] = e++;
    return 0;
}

int newaddedge(int u, int v)
{
    newEdge[e].to = v;
    newEdge[e].next = newhead[u];
    newhead[u] = e++;
    return 0;
}void tarjan(int u)
{
    int v;
    dfn[u] = low[u] = ++cnt;//开始时dfn[u] == low[u]
    S[top++] = u;//不管三七二十一进栈
    vis[u] = true;
    for (int i=head[u]; i!=-1; i=Edge[i].next)
    {
        v = Edge[i].to;
        if (dfn[v] == 0)//如果v点还未遍历
        {
            tarjan(v);//向下遍历
            low[u] = low[u] < low[v] ? low[u] : low[v];//确保low[u]最小
        }
        else if (vis[v] && low[u] > dfn[v])//v在栈中,修改low[u]
            low[u] = dfn[v];
    }
    if (dfn[u] == low[u])//u为该强连通分量中遍历所成树的根
    {
        ++scc;//缩点后点的编号是从1开始的
        do
        {
            v = S[--top];//栈中所有到u的点都属于该强连通分量,退栈
            vis[v] = false;
            belong[v] = scc;
        } while (u != v);//????????
    }

}

int solve()
{
    scc = top = cnt = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(vis, false, sizeof(vis));
    for (int u=1; u<=n; ++u)
        if (dfn[u] == 0)
            tarjan(u);
    return scc;
}
int cntfenliang[V];
void count_deg()
{
    memset(indeg, 0, sizeof(indeg));
    memset(outdeg, 0, sizeof(outdeg));
    for (int u=1; u<=n; ++u)
        for (int i=head[u]; i!=-1; i=Edge[i].next)
        {
            int v = Edge[i].to;
            if (belong[u] != belong[v])
            {
                indeg[belong[v]]++;
                outdeg[belong[u]]++;
            }
        }
}

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

        int scc=solve();
        count_deg();
        //计算一个强联通分量里有几个点
        memset(cntfenliang,0,sizeof(cntfenliang));
        for(int i=1;i<=n;i++)
            cntfenliang[belong[i]]++;
        //遍历原图建新图
        memset(newhead,-1,sizeof(newhead));
        e=0;
        for(int j=1;j<=n;j++)
        {
            for(int i=head[j];i!=-1;i=Edge[i].next)
            {
                int temp=Edge[j].to;
                if (belong[j] != belong[temp])
                {
                    newaddedge(belong[j],belong[temp]);
                }
            }
        }
        int outc=0;
        int a;
        int cnt0=0;
        for (int i=1; i<=scc; ++i)
        {
            if (outdeg[i] == 0)
            {
                outc++;
                a=i;
            }
        }
        if(outc==1)
        {
            printf("%d\n",cntfenliang[a]);
        }
        else
            printf("0\n");
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值