poj 2186 强连通分量

poj 2186 强连通分量

传送门

Popular Cows
Time Limit: 2000MS      Memory Limit: 65536K
Total Submissions: 33414        Accepted: 13612
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. 

我们可以将一个强联通分量看成一个点进行处理,因为这个强连通分量中的点都是相互可达的,那么只要其中一头牛成为红人,那么其他牛也是一样的,同时我们可以得到两个结论

  1. 最终答案必然只是一个强连通分量(如果有两个,那么根据所有点必须可达这个点的条件,那么这两个点集必然属于一个强连通分量,与假设不合,证明成立)
  2. 最终答案就是拓扑排序最后的那个强连通分量,这是根据拓扑排序的性质得来的
    所以我们只需要求出那个强连通分量,最终再反向dfs验证是否可达每个点,这题就解出来了。
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#define ll long long
#define inf 1000000000LL
#define mod 1000000007
using namespace std;
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
const int N=1e4+10;
const int M=5e4+10;
int A[M],B[M],n,m;
vector<int> G[N];       //图
vector<int>rG[N];       //反向图
vector<int>vs;          //后序遍历的顶点列表
bool vis[N];
int  cmp[N];             //所属强连通分量的拓扑序
int sum[N];
void Addedge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}
void dfs(int v){
    vis[v]=true;
    for(int i=0;i<G[v].size();i++){
        if(!vis[G[v][i]]) dfs(G[v][i]);
    }
    vs.push_back(v);
}
void rdfs(int v,int k){
    vis[v]=true;
    cmp[v]=k;
    sum[k]++;
    for(int i=0;i<rG[v].size();i++){
         if(!vis[rG[v][i]]) rdfs(rG[v][i],k);
    }
}
int scc(){
    memset(vis,0,sizeof(vis));
    vs.clear();
    for(int v=0;v<n;v++){
          if(!vis[v]) dfs(v);
    }
    memset(vis,0,sizeof(vis));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
           if(!vis[vs[i]]) rdfs(vs[i],k++); //遍历每个联通分量的点集
    }
    return k;
}
int main(){
   // while(true)
    {
        n=read();m=read();
        for(int i=0; i<m; i++){
            A[i]=read();B[i]=read();
             Addedge(A[i]-1,B[i]-1);
        }
        int count=scc();
        int u=0,num=sum[count-1];
        for(int v=0;v<n;v++){
            if(cmp[v]==count-1){
                u=v;
                break;
            }
        }
        memset(vis,0,sizeof(vis));
        rdfs(u,0);
        for(int v=0;v<n;v++){
            if(!vis[v]){
                num=0;
                break;
            }
        }
        printf("%d\n",num);
    }
    return 0;
}

/*
5 5
1 2
1 3
2 4
4 5
5 2
*/

转载于:https://www.cnblogs.com/zsyacm666666/p/6807398.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值