1 条题解

  • 0
    @ 2025-5-22 20:12:08

    题意分析

    题目描述了一个牛群中奶牛之间的 “受欢迎” 关系,这种关系具有传递性。例如,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么 A 也会认为 C 受欢迎。我们需要找出被所有其他奶牛都认为受欢迎的奶牛数量。 关键点: 传递性:如果 A 认为 B 受欢迎,B 认为 C 受欢迎,则 A 自动认为 C 受欢迎。

    目标:统计被所有其他奶牛直接或间接认为受欢迎的奶牛数量。

    解题思路

    问题转化

    每头奶牛视为一个节点,每个有序对 (A, B) 表示从 A 到 B 的一条有向边。

    若存在一头奶牛 C,所有其他奶牛都能通过有向边到达 C,则 C 是被所有奶牛认为受欢迎的。

    强连通分量(SCC)

    若两头奶牛 A 和 B 互相认为对方受欢迎,则它们属于同一个强连通分量(SCC)。

    在同一个 SCC 中的奶牛互相可达,因此它们要么全部被其他奶牛认为受欢迎,要么都不被。

    缩点与 DAG

    将每个 SCC 缩成一个点,形成一个有向无环图(DAG)。

    若存在一个 SCC 是 DAG 中的唯一出度为 0 的节点,则该 SCC 中的所有奶牛均被其他所有奶牛认为受欢迎。

    算法步骤

    Tarjan 算法:找出所有 SCC 并缩点。

    统计出度:在缩点后的 DAG 中,统计每个 SCC 的出度。

    唯一性检查:若恰好存在一个出度为 0 的 SCC,则其大小即为答案;否则无解。

    复杂度

    时间复杂度:O (N + M),Tarjan 算法可在线性时间内找到所有 SCC。

    代码

    #include<iostream>
    #include<math.h>
    #include<stdio.h> // 添加标准输入输出头文件
    #include<stdlib.h> // 添加标准库头文件,包含malloc等函数
    #include<string.h> // 添加字符串处理头文件,包含memset函数
    using namespace std;
    bool visit[10000];
    typedef struct enode{
       int adj; 
       struct enode *next;        
    }enode;
    typedef struct vnode{
        enode *find;
    }vnode;
    typedef vnode List[10000];
    typedef struct graphic{
        List list;
        int n,e;       
    }graphic;
    typedef struct Edge{
        int s, e;
    } Edge;
    Edge E[100000];
    int order[10000],id[10000],in[10000];
    int cnt;
    void create(graphic *g,graphic *g1){
        scanf("%d %d",&g->n,&g->e);
        g1->n=g->n; g1->e=g->e;   
        for(int i=0;i<g->n;i++){
            g->list[i].find=NULL;
            g1->list[i].find=NULL;
        }   
        for(int i=0;i<g->e;i++){
            enode *p=(enode *)malloc(sizeof(enode));
            int k,m;   
            scanf("%d%d",&k,&m);
            k--; m--;
            E[i].s=k; E[i].e=m;
            p->adj=m; p->next=g->list[k].find;
            g->list[k].find=p;
            p=(enode *)malloc(sizeof(enode));
            p->adj=k;  p->next=g1->list[m].find;
            g1->list[m].find=p;    
        }
    }
    void dfs1(graphic *g,int i){
           enode *p=g->list[i].find;;
           visit[i]=true;
           while(p) {
               if(!visit[p->adj]) dfs1(g,p->adj);
               p=p->next;        
           }  
           order[cnt++]=i;
    }
    void dfs(graphic *g,int i){
           enode *p=g->list[i].find;;
           visit[i]=true;
           id[i]=cnt;
           while(p) {
               if(!visit[p->adj])dfs(g,p->adj);
               p=p->next;        
           }  
    }
    void dfs2(graphic *g,int i){
         enode *p=g->list[i].find;
         visit[i]=true;
         while(p){
              if(id[i]!=id[p->adj]) in[i]++;
              if(!visit[p->adj]) dfs(g,p->adj);
              p=p->next;         
         }
    }
    int main(){
       int pos;
       graphic *g=(graphic *)malloc(sizeof(graphic));
       graphic *g1=(graphic *)malloc(sizeof(graphic));
       create(g,g1);
       memset(visit,0,sizeof(visit)); cnt=0;
       for(int i=0;i<g->n;i++)
           if(!visit[i]) dfs1(g1,i);
       memset(visit,0,sizeof(visit)); cnt=0;
       for(int i=g->n-1;i>=0;i--){
           if(!visit[order[i]]){ 
                dfs(g,order[i]);
                cnt++;        
           }
       }
       int s,e;
       for (int i = 0; i < g->e; i++){ //一个部落能通往其他部落则为1 
            s = id[E[i].s];
            e = id[E[i].e];
            if (s != e)  in[s]++;
        }
        int scnt = cnt;
        cnt = 0;
        for(int i = 0; i < scnt; i++){ //如果强连通则只有一个为0 
            if (in[i] == 0){
                pos = i; //保存了最后的那个部落 
                cnt++;
            }
        }
        if (cnt != 1) printf("0\n");
        else{
            cnt = 0;
            for (int i = 0; i < g->n; i++)
                if (in[id[i]] == pos) //求出最后那个部落的人数 
                    cnt++;
            printf("%d\n", cnt);
        }
       system("pause");
       return 0;
    }
    ```
    
    ```
    • 1

    信息

    ID
    1187
    时间
    2000ms
    内存
    64MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者