算法主要参考这篇解题报告点击打开链接,利用的是Kosaraju算法和缩点,给每个强连通分量染上颜色,缩成点后统计每个点的出度。
/******************************************************************************* # Author : Neo Fung # Email : [email protected] # 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; }