【受欢迎的牛】解题报告

今天欧教让我们学习一下强连通分量的tarjan算法。


【题目名称】:受欢迎的牛

Description 

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


Input 
第一行两个数N,M。 
接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B) 
Output 
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input 
3 3
1 2
2 1
2 3
Sample Output 
1
【数据范围】 

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



交了四次,WA完了。poj就是烦。。

和Wjj对拍了10分钟,没有错误。。。

这道题首先考虑没有环的情况。如果没有环,则可知,如果出度为0的点只有一个,那么所有的牛都认为他受欢迎。如果超过一个。则没有这样的牛。

所以可以考虑tarjan强连通缩点,如果出度为0的强连通块只有一个,那么就输出其中点的数量。其实tarjan并不难,只是一开始写忘了考虑多个连通块。

对于

这种情况,5不会被加入<5>这个强连通块。


关于tarjan算法的解释:http://www.byvoid.com/blog/scc-tarjan/


#include <iostream>
#include <bitset>
using std::cout;
using std::cin;

long n;

long tt = 0;
long t[10002];
long l[10002];
bool used[10002];
long top = 0;
long mm = 0;
long fl2[10002];
long fl[10002];
long stack[10002];
bool instack[10002];
long out[10002];

struct node
{
	long index;
	node* next;
};
node* dm[10002];

void insert(long a,long b)
{
	node* tmp = new node;
	tmp->index = b;
	tmp->next = dm[a];
	dm[a] = tmp;
}

void tarjan(long p)
{
	t[p] = l[p] = ++tt;
	stack[++top] = p;
	instack[p] = true;
	node* ths = dm[p];
	while (ths)
	{
		long i = ths->index;
		if (!used[i])
		{
			used[i] = true;
			tarjan(i);
			if (l[i]<l[p])l[p]=l[i];
		}
		else if(instack[i]&&t[i]<l[p])
			l[p] = t[i];
		ths = ths->next;
	}
	if (l[p]==t[p])
	{
		mm++;
		while (stack[top]!=p)
		{
			fl[stack[top]]=mm;
			fl2[mm]++;
			instack[stack[top]] = false;
			top--;
		}
		fl[p] = mm;//打错成fl[stack[p]] 
		fl2[mm]++;
		instack[p] = false;
		top--;
	}
}

int main()
{
	freopen("ans.out","w",stdout);
	freopen("poj2186.in","r",stdin);
	long tt;
	cin >> n >> tt;
	for (long i=1;i<tt+1;i++)
	{
		long a;long b;
		cin >> a >> b;
		insert(a,b);
	}
	for (long i=1;i<n+1;i++)
	{//这里之前没有考虑多个连通块,所以错了 
		if (!used[i])
		{
			top = 0;
			tarjan(i);
			used[i] = true;
		}
	}

	for (long i=1;i<n+1;i++)
	{
		node* ths = dm[i];
		while (ths)
		{
			long j = ths->index;
			if (fl[i]!=fl[j])
			{
				out[fl[i]]++;				
			}
			ths = ths->next;
		}
	}
	long cnt = 0;
	long k = 0;
	for (long i=1;i<mm+1;i++)
	{
		if (out[i]==0)
		{
			cnt ++;
			if (cnt>1){cout<<0;return 0;}
			k = i;
		}
	}
	cout << fl2[k];
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值