POJ 2186 Popular Cows(强联通分量缩点+tarjan算法)

Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 30846 Accepted: 12531

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.

Source

1.题意

给定一个有向图,让你寻找这样从任意点都可以到达的点的个数,如果搞清楚了算法那么我们大概的思路还是比较清晰的,首先我们要用到这样一个定理:在DAG上的唯一一个出度为0的点,那么任这个图上任一点一定可以到达这个点(很直观也很好证明,因为无环,沿着边只能前进,最终一定汇聚到出度为0的点上),那么基于这样一个理论我们稍加思考,一个强联通分量中的点一定是可以相互到达的,那么要这个联通分量如果要被其他任一点到达的话那就要满足,在进行寻找强连通分量并进行缩点之后,这个强连通分量的出度是0且是唯一的出度为0的强联通分量,那么答案就很明显了,如果有多个出度为0的强联通分量,那么结果就是0(显而易见DAG上的任意两个出度为0的点无法相互到达),如果有且仅有一个出度为零的强联通分量,那么这个强联通分量中的点的数量就一定是最后的答案。

我用的是tarjan+邻接表来搞的

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <stack>
using namespace std;
const int N =10010, M=100010;
struct node
{
    int to, next;
}edge[M];
int head[N], low[N], dfn[N], sta[N], belg[N], num[N],out[N],first[N],next[N],uu[M],vv[M];
bool vis[N];
int scc,index,tot;
stack <int> st;
int min(int a,int b)
{
	if(a<b) return a;
	else return b;
}
void tarbfs(int u)
{
    int i,j,k,v;
    low[u]=dfn[u]=++index;
    st.push(u);
    vis[u]=1;  
    k=first[u];
    while(k!=-1)
    {
        v=vv[k];
        if(!dfn[v])
        {
            tarbfs(v);
            if(low[u]>low[v]) low[u]=low[v];
        }
        else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
        k=next[k];
    }
    if(dfn[u]==low[u])
    {
        scc++;
        do
        {
            v=st.top();
            st.pop();
            vis[v]=0;
            belg[v]=scc;
            num[scc]++;
        }
        while(v!=u) ;
    }
} 
void Tarjan(int n)
{
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(num,0,sizeof(num));
    memset(low,0,sizeof(low));
    while(!st.empty()) st.pop();
    index=scc=top=0;
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarbfs(i);
}
void init()
{
    tot=0;
    memset(first,-1,sizeof(first));
    memset(out,0,sizeof(out));
}

void addedge(int u,int v)
{
	uu[tot]=u; vv[tot]=v; next[tot]=first[u]; first[u]=tot;
	tot++;
}
int main()
{
	//freopen("input.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		init();
		for(int i=1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			addedge(u,v);
		}
		Tarjan(n);
		for(int i=1;i<=n;i++)
		{
			int k=first[i];
			while(k!=-1)
			{
				int u=i, v=vv[k];
				if(belg[u]!=belg[v])
				{
					out[belg[u]]++;
				}
				k=next[k];
			}
		}
		int counter=0,p=0;
		for(int i=1;i<=scc;i++)
		{
			if(out[i]==0) counter++,p=i;	
		}
		if(counter==1) printf("%d\n",num[p]);
		else printf("0\n");
	}
	return 0;
}


 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值