洛谷P2341受欢迎的牛

传送门啦

这是一个tarjan强连通分量与出度结合的例题。

先明确一下题意,如果这个点(缩点之后的)没有出度,这个点才能成为明星牛(明星牛的定义是:所有牛都喜欢他才可以)。

由于我们进行了缩点,所以我就另外开一个数组num[i]:表示这个强连通分量中有多少个点。

    int sum = 0;
    for(int i=1;i<=cnt;i++)
      if(!chu[i])  ans = num[i] , sum++;
    if(sum >= 2)  printf("0");
    else printf("%d",ans);

以上就是怎样处理最后的答案:

如果我们有两个或以上出度为 0 点(缩点后的),说明这几个出度为 0 的点(缩点后)互相不喜欢,所以没有明星牛。

否则就有明星牛(明星牛的个数就是出度为 0 的那个强连通分量中点的个数),很好想吧:那个强连通分量中的牛互相喜欢,而其他强连通分量中的牛也喜欢他们,等量代换所有牛都喜欢他

首先是tarjan缩点中的几个数组:

 dfn[i]:i点的时间戳

 low[i],表示这个点以及其子孙节点连的所有点中dfn最小的值

 stack[],表示当前所有可能能构成是强连通分量的点。

 ins[i],表示 i 是否在stack[ ]数组中

 num[i],表示第 i 个强连通分量中有多少个点

 belong[i],表示第 i 点在哪一个强连通分量里
 

下面就是AC代码了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 4;
const int maxm = 5e4 + 4;

int n,m,u,v;
int head[maxn],tot;
int dfn[maxn],low[maxn],ind;
int stack[maxn],top,num[maxn],belong[maxn],cnt;
bool ins[maxn];
int chu[maxn],ans;
struct Edge{
    int from,to,next;
}edge[maxm];

void add(int u,int v){
    edge[++tot].from = u;
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot;
}

int read(){
    char ch = getchar();
    int f = 1 , x = 0;
    while(ch > '9' || ch < '0'){
        if(ch == '-')  f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar(); 
    }
    return x * f;
}

void tarjan(int x){
    dfn[x] = low[x] = ++ind;
    stack[++top] = x;
    ins[x] = true;
    for(int i=head[x];i;i=edge[i].next){
        int v = edge[i].to;
        if(ins[v]) low[x] = min(low[x] , dfn[v]);
        if(!dfn[v]){
            tarjan(v);
            low[x] = min(low[x] , low[v]);
        }
    }
    int k = 0;
    if(dfn[x] == low[x]){
        cnt++;
        do{
            k = stack[top];
            num[cnt]++;
            top--;
            ins[k] = false;
            belong[k] = cnt;
        } while(k != x);
    }
} 

int main(){
    n = read();  m = read();
    for(int i=1;i<=m;i++){
        u = read();  v = read();
        add(u , v);
    }
    for(int i=1;i<=n;i++)
      if(!dfn[i])  tarjan(i);
    for(int i=1;i<=m;i++){
        if(belong[edge[i].from] != belong[edge[i].to]){
            chu[belong[edge[i].from]]++;
        }
    }
    int sum = 0;
    for(int i=1;i<=cnt;i++)
      if(!chu[i])  ans = num[i] , sum++;
    if(sum >= 2)  printf("0");
    else printf("%d",ans);
    return 0;
}

转载于:https://www.cnblogs.com/Stephen-F/p/9884646.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值