• 受欢迎的牛 [HAOI2006] [强连通] [传递闭包(划)]


    Description

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

    Input

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

    Output

    一个数,即有多少头牛被所有的牛认为是受欢迎的。

    Sample Input

    3 3

    1 2

    2 1

    2 3

    Sample Output

    1

    Hint

    10%的数据N<=20,M<=50
    30%的数据N<=1000,M<=20000
    70%的数据N<=5000,M<=50000
    100%的数据N<=10000,M<=50000

    Solution

    首先,如果数据很小的话可以用传递闭包对吧,但是N到了1e5就显然不行了。

    显然如果在一个环里的各个点的传递是互达的,由此我们可以扩展到一个强连通分量也是这样。

    于是我们就可以想到tarjan缩点。

    缩完点后怎么办呢?愚蠢的我想到一个点的入度=点数-1就对答案产生贡献,显然是不对的(如 3->2->1)。

    于是我第一遍只有70分,(这样都有70分可能是数据太水了)。

    脑子不好使的我冒着被卡的风险在缩完点后使用传递闭包(不要问我为什么我这么喜欢传递闭包),居然过了!(可能是数据太水了)

    然后我便看正解,发现果然还是大佬们聪明一点。

    对于缩完点后的点x

    i)如果出度!=0,那么肯定有没指向自己的点,(如果有指出去后又指回来肯定在连通分量内)

    ii)如果出度==0,似乎这个连通分量内的点就是答案,但是如果有多个出度为0的点,就说明还有多个独立的区域,那也不行。

         所以出度==0的点有且只有一个的时候即为答案

    Code (传递闭包版)

     1 #include<set>
     2 #include<stack>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<algorithm>
     7 #define RG register int
     8 #define rep(i,a,b)    for(RG i=a;i<=b;i++)
     9 #define per(i,a,b)    for(RG i=a;i>=b;i--)
    10 #define inf (1<<30)
    11 #define maxn 10005
    12 #define maxm 500005
    13 #define add(x,y) e[++cnt].u=u,e[cnt].v=v,e[cnt].next=head[u],head[u]=cnt
    14 using namespace std;
    15 stack<int> stk;
    16 set<int> st[maxn];
    17 int n,m,cnt,id,sid,ans;
    18 int head[maxn],scc[maxn],dfn[maxn],low[maxn],vis[maxn],ind[maxn],sz[maxn],oud[maxn];
    19 int gra[1000][1000];
    20 struct E{
    21     int u,v,next;
    22 }e[maxm];
    23 inline int read()
    24 {
    25     int x=0,f=1;char c=getchar();
    26     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    27     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    28     return x*f;
    29 }
    30 
    31 void tarjan(int u,int fa)
    32 {
    33     low[u]=dfn[u]=++id;
    34     stk.push(u);vis[u]=1;
    35     for(int i=head[u];i;i=e[i].next)
    36     {
    37         int v=e[i].v;
    38         if(!dfn[v])
    39         {
    40             tarjan(v,u);low[u]=min(low[u],low[v]);
    41         }
    42         else if(vis[v])    low[u]=min(low[u],dfn[v]);
    43     }
    44     if(low[u]==dfn[u])
    45     {
    46         ++sid;int x;
    47         do{
    48             x=stk.top(),stk.pop();
    49             vis[x]=0,scc[x]=sid,sz[sid]++;
    50         }while(x!=u);
    51     }
    52 }
    53 
    54 
    55 
    56 int main()
    57 {
    58     n=read(),m=read();
    59     RG u,v;rep(i,1,m) u=read(),v=read(),add(u,v);
    60     rep(i,1,n)    if(!scc[i])    tarjan(i,0);
    61     rep(i,1,cnt)
    62     {
    63         int x=scc[e[i].u],y=scc[e[i].v];
    64         if(x!=y)
    65             gra[x][y]=1;
    66     }
    67     rep(k,1,sid)
    68         rep(i,1,sid)
    69             rep(j,1,sid)
    70                 if(gra[i][k]&&gra[k][j])gra[i][j]=1;
    71     rep(i,1,sid)
    72     {
    73         int flg=0;
    74         rep(j,1,sid)
    75             if(i!=j&&!gra[j][i]) flg=1;
    76         if(!flg) ans+=sz[i];
    77     }
    78     cout<<ans;
    79     return 0;
    80 }
    >>点击查看代码<<

     1 #include<set>
     2 #include<stack>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<algorithm>
     7 #define RG register int
     8 #define rep(i,a,b)    for(RG i=a;i<=b;i++)
     9 #define per(i,a,b)    for(RG i=a;i>=b;i--)
    10 #define inf (1<<30)
    11 #define maxn 10005
    12 #define maxm 500005
    13 #define add(x,y) e[++cnt].u=u,e[cnt].v=v,e[cnt].next=head[u],head[u]=cnt
    14 using namespace std;
    15 stack<int> stk;
    16 set<int> st[maxn];
    17 int n,m,cnt,ccnt,id,sid,ans;
    18 int head[maxn],hh[maxn],scc[maxn],dfn[maxn],low[maxn],vis[maxn],ind[maxn],sz[maxn],oud[maxn];
    19 int gra[1000][1000];
    20 struct E{
    21     int u,v,next;
    22 }e[maxm];
    23 struct EE{
    24     int v,next;
    25 }edge[maxm];
    26 inline int read()
    27 {
    28     int x=0,f=1;char c=getchar();
    29     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    30     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    31     return x*f;
    32 }
    33 
    34 void tarjan(int u,int fa)
    35 {
    36     low[u]=dfn[u]=++id;
    37     stk.push(u);vis[u]=1;
    38     for(int i=head[u];i;i=e[i].next)
    39     {
    40         int v=e[i].v;
    41         if(!dfn[v])
    42         {
    43             tarjan(v,u);low[u]=min(low[u],low[v]);
    44         }
    45         else if(vis[v])    low[u]=min(low[u],dfn[v]);
    46     }
    47     if(low[u]==dfn[u])
    48     {
    49         ++sid;int x;
    50         do{
    51             x=stk.top(),stk.pop();
    52             vis[x]=0,scc[x]=sid,sz[sid]++;
    53         }while(x!=u);
    54     }
    55 }
    56 
    57 
    58 
    59 int main()
    60 {
    61     n=read(),m=read();
    62     RG u,v;rep(i,1,m) u=read(),v=read(),add(u,v);
    63     rep(i,1,n)    if(!scc[i])    tarjan(i,0);
    64     rep(i,1,cnt)
    65     {
    66         int x=scc[e[i].u],y=scc[e[i].v];
    67         if(x!=y)
    68             gra[x][y]=1;
    69     }
    70     rep(k,1,sid)
    71         rep(i,1,sid)
    72             rep(j,1,sid)
    73                 if(gra[i][k]&&gra[k][j])gra[i][j]=1;
    74     rep(i,1,sid)
    75     {
    76         int flg=0;
    77         rep(j,1,sid)
    78             if(i!=j&&!gra[j][i]) flg=1;
    79         if(!flg) ans+=sz[i];
    80     }
    81     cout<<ans;
    82     return 0;
    
  • 相关阅读:
    js图片滑动展示
    那些好像失败了却很有趣的奇怪产物——傅里叶变换图片篇
    啊,满足了我对javaBean的所有幻想,记录一个神器:Lombok!
    十几行代码将mock生成的json数据转为sql的insert语句
    python之三目运算符的替代品?
    【python爬虫】每天统计一遍up主粉丝数!
    大项目之网上书城(十二)——完成啦
    大项目之网上书城(十一)——前台完成
    大项目之网上书城(十)——自动登录
    vs2019 创建vue项目
  • 原文地址:https://www.cnblogs.com/ibilllee/p/8710708.html
Copyright © 2020-2023  润新知