算法主要参考这篇解题报告点击打开链接,利用的是Kosaraju算法和缩点,给每个强连通分量染上颜色,缩成点后统计每个点的出度。
/*******************************************************************************
# Author : Neo Fung
# Email : neosfung@gmail.com
# Last modified: 2011-09-23 23:31
# Filename: POJ2186 Popular Cows.cpp
# Description : Kosaraju算法+缩节点
******************************************************************************/
// POJ2186 Popular Cows.cpp : Defines the entry point for the console application.
//
// #include "stdafx.h"
// #define DEBUG
#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <memory.h>
#include <stack>
#define MAX 10010
using namespace std;
struct NODE
{
int to;
NODE *next;
}*v[MAX],*rv[MAX],node[10*MAX];
int nodecount,n,m;
int visit[MAX],color[MAX],sum4clolr[MAX],dag_out[MAX];
stack<int> mstack;
void init(void)
{
memset(v,'\0',sizeof(v));
memset(rv,'\0',sizeof(rv));
memset(visit,0,sizeof(visit));
memset(color,0,sizeof(color));
memset(sum4clolr,0,sizeof(sum4clolr));
memset(dag_out,0,sizeof(dag_out));
while(!mstack.empty()) mstack.pop();
nodecount=0;
}
void input(void)
{
int from,to;
for(int i=0;i<m;++i)
{
scanf("%d %d",&from,&to);
node[nodecount].to=to;
node[nodecount].next=v[from];
v[from]=&node[nodecount++];
node[nodecount].to=from;
node[nodecount].next=rv[to];
rv[to]=&node[nodecount++];
}
}
void DFS(int u)//第一次深度遍历,把遍历结果入栈
{
visit[u]=1;
NODE *head=v[u];
while(head)
{
if(!visit[head->to])
DFS(head->to);
head=head->next;
}
mstack.push(u);
}
void DFS_T(int u,int type)//
{
visit[u]=1;
color[u]=type; //给每个节点染色,使得同一个强连通分量都有同一种颜色
++sum4clolr[type]; //记录下每一种颜色的节点数
NODE *head=rv[u];
while(head)
{
if(!visit[head->to])
DFS_T(head->to,type);
head=head->next;
}
}
void kosaraju(void)
{
for(int i=1;i<=n;++i) //第一次DFS搜索所有节点
if(!visit[i])
DFS(i);
memset(visit,0,sizeof(visit));
int dagcount=0;
while(!mstack.empty())//第二次DFS遍历
{
int num=mstack.top();
mstack.pop();
if(!visit[num])
DFS_T(num,dagcount++);
}
//缩点,把每一个强连通分量视为一个点,则整个图成为一个DAG,记录下每个点(即强连通分量)到别的点的出度
for(int i=1;i<=n;++i)
{
NODE *head=v[i];
while(head)
{
if(color[i]!=color[head->to]) //如果点有到别的强连通分量的支路
++dag_out[color[i]];
head=head->next;
}
}
int index=-1;
for(int i=0;i<dagcount;++i) //搜索每一个强连通分量,如果有且只有一个是出度为0的,则强连通分量里的节点数就是结果,否则数据无解
if(dag_out[i]==0)
if(index==-1)
index=sum4clolr[i];
else
{
printf("0\n");
return;
}
if (index==-1)
printf("0\n");
else
printf("%d\n",index);
}
int main(void)
{
#ifdef DEBUG
freopen("data.txt","r",stdin);
#endif
while(scanf("%d %d",&n,&m)!=EOF)
{
init();
input();
kosaraju();
}
return 0;
}