POJ 2186 Popular Cows

22 篇文章 0 订阅

    这题用的是Tarjan算法, 先求出强连通分量的个数, 如果为一, ans就是牛的个数, 如果不是, 求出出度为零的强连通分量的个数, 如果只有一个, 输出这个强连通分量里牛的个数, 如果不止一个, 输出0, 因为不存在牛被所有牛喜欢。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <stack>
#define mem(a) memset(a, 0, sizeof(a))
using namespace std;

int dfn[10005], low[10005], vis[10005], num[10005], jilu[10005], vis2[10005], w, n, m, flag, ans = 0;
stack<int> q;

struct node
{
	int a;
	node *next;
}point[10005];

void Tarjan(int s)
{
	int i, t;
	node *v;
	q.push(s);
	vis[s] = 1;
	dfn[s] = low[s] = ++flag;
	v = point[s].next;
	while(v)
	{
		if(vis[v->a] == 0)
		{
			Tarjan(v->a);
			low[s] = min(low[s], low[v->a]);
		}
		else
		{
			low[s] = min(low[s], dfn[v->a]);
		}
		v = v->next;
	}
	if(low[s] == dfn[s])
    {
        jilu[w] = s;
        w++;
        ans++;
        do
        {
            t = q.top();
            vis[t] = 2;
            vis2[t] = s;
            q.pop();
        }while(s != t);
    }
}

int main(int argc, char *argv[])
{
	int i, j, k, a, b, o = 0, flag2, res, flag3;
	scanf("%d%d",&n, &m);
	flag = 0;
	flag2 = 0;
	flag3 = 0;
	res = 0;
	w = 0;
	mem(dfn);
	mem(low);
	mem(vis);
	mem(vis2);
	mem(num);
	mem(point);
	for(i = 0;i < m;i++)
	{
		scanf("%d%d",&a, &b);
		num[a]++;
		node *p;
		p = (node*)malloc(sizeof(node));
		p->a = b;
		p->next = point[a].next;
		point[a].next = p;
	}
	for(i = 1;i <= n;i++)
	{
		if(vis[i] == 0)
		{
			flag = 0;
			Tarjan(i);
		}
	}
	if(ans == 1)
	printf("%d\n", n);	
	else
	{
		for(i = 0;i < w;i++)
		{
			flag3 = 0;
			for(j = 1;j <= n;j++)
			{
				if(vis2[j] == jilu[i])
				{
					node *p;
					p = point[j].next;
					while(p)
					{
						if(vis2[p->a] != jilu[i])
						{
							flag3 = 1;
						}
						p = p->next;
					}
				}
			}
			if(flag3 == 1)
			o++;
			else
			flag2 = i;
		}
		if((ans - o) == 1)
		{
			for(i = 1;i <= n;i++)
			{
				if(vis2[i] == jilu[flag2])
				res++;
			}
			printf("%d\n", res);
		}
		else
		{
			printf("0\n");
		}
	}	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值