zoukankan      html  css  js  c++  java
  • Popular Cows

    http://poj.org/problem?id=2186

    题意:有n头奶牛,给出m对奶牛之间的关系(a,b),表示a欢迎b。欢迎关系是单向可传递的,并且每个奶牛都是欢迎自己的。求出被所有奶牛欢迎的奶牛的数量。

    思路:求出所有的连通分量(Tarjan算法),然后求出每个连通分量的出度,如果出度为0的连通分量大于一个,则该图不连通,输出0;如果出度为0的连通分量只有一个,则在该连通分量里的点即为受所有奶牛欢迎的奶牛,输出该连通分量里的点数即可。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <algorithm>
      4 #include <stack>
      5 const int N=100010;
      6 using namespace std;
      7 struct node
      8 {
      9     int u,v,next;
     10 } edge[N];
     11                           //dfn[i]表示点i的深度优先数;
     12 int dfn[N],low[N],head[N];//low[i]表示点i可到达的最低深度优先数
     13 int Conn_num[N],out[N];   //Conn_num[i]表示点i所属的连通分量的编号;
     14 int n,m,cnt,dfs_clock,Conn_cnt;
     15 stack<int>S;
     16 
     17 void init()
     18 {
     19     cnt = 0;
     20     dfs_clock = 0;
     21     Conn_cnt = 0;
     22     memset(dfn,0,sizeof(dfn));
     23     memset(low,0,sizeof(low));
     24     memset(out,0,sizeof(out));
     25     memset(Conn_num,0,sizeof(Conn_num));
     26     memset(head,-1,sizeof(head));
     27 }
     28 void add(int u,int v)
     29 {
     30     edge[cnt].u = u;
     31     edge[cnt].v = v;
     32     edge[cnt].next = head[u];
     33     head[u] = cnt++;
     34 }
     35 
     36 void dfs(int u)//Tarjan算法
     37 {
     38     dfn[u]=low[u]=++dfs_clock//设定初值
     39     S.push(u);//将节点u压入栈中
     40     for (int i = head[u]; i!=-1; i=edge[i].next)//遍历u的临接点
     41     {
     42         int v = edge[i].v;
     43         if (!dfn[v])//如果改点的深度优先数为0(即没有搜索过)
     44         {
     45             dfs(v);//继续向下找
     46             low[u] = min(low[u],low[v]);//回溯过程中计算low[]的值
     47         }
     48         else if(!Conn_num[v])//v不在连通分量中,即v还在栈中
     49         {
     50             low[u] = min(low[u],dfn[v]);
     51         }
     52     }
     53     if (dfn[u]==low[u])//找到一个连通分量
     54     {
     55         ++Conn_cnt;//连通分量计数
     56         while(1)//将栈里属于同一个连通分量的点弹出
     57         {
     58             int v = S.top();
     59             S.pop();
     60             Conn_num[v] = Conn_cnt;//表示点v在第Conn_cnt个连通分量里
     61             if (v==u)
     62                 break;
     63         }
     64     }
     65 }
     66 int main()
     67 {
     68     int u,v;
     69     while(~scanf("%d%d",&n,&m))
     70     {
     71         init();
     72         for (int i = 0; i < m; i++)
     73         {
     74             scanf("%d%d",&u,&v);
     75             add(u,v);
     76         }
     77         for (int i = 1; i <= n; i++)
     78         {
     79             if (!dfn[i])
     80                 dfs(i);
     81         }
     82         for (int i = 1; i <= n; i++)
     83         {
     84             for (int j = head[i]; j!=-1; j=edge[j].next)//遍历所有与i点相邻的点
     85             {
     86                 int v = edge[j].v;
     87                 if (Conn_num[i]!=Conn_num[v])//如果i点与v点相连但是属于不同的连通分量,说明这两个连通分量之间存在有向边
     88                     out[Conn_num[i]]++;      //i所属的连通分量的出度+1
     89             }
     90         }
     91         int sum=0,pos=0;
     92         for (int i = 1; i <= Conn_cnt; i++)//遍历所有的连通分量
     93         {
     94             if (!out[i])
     95             {
     96                 sum++;//计算出度等于0的连通分量的个数
     97                 pos = i;//标记出度等于0的连通分量的编号
     98             }
     99         }
    100         if (sum!=1)//图不连通
    101             printf("0
    ");
    102         else       //出度等于0的连通分量只有一个
    103         {
    104             int ans = 0;
    105             for (int i = 1; i <= n; i++)
    106             {
    107                 if(Conn_num[i]==pos)//计算该连通分量(即出度为0的连通分量)中的点的个数
    108                     ans++;
    109             }
    110             printf("%d
    ",ans);
    111         }
    112     }
    113     return 0;
    114 }
    View Code

    关于Tarjan算法的介绍:https://www.byvoid.com/blog/scc-tarjan/

  • 相关阅读:
    codevs 1102 采药 2005年NOIP全国联赛普及组
    codevs 1058 合唱队形 2004年NOIP全国联赛提高组
    动归题目
    友好城市//未测,不知对错
    codevs 1044 拦截导弹 1999年NOIP全国联赛提高组
    codevs 5294 挖地雷
    codevs 1576 最长严格上升子序列
    [BZOJ3289]Mato的文件管理
    [CodeVS1299]切水果
    [TYVJ1473]校门外的树3
  • 原文地址:https://www.cnblogs.com/lahblogs/p/3548708.html
Copyright © 2011-2022 走看看