您的位置:首页 > 运维架构

POJ 2186 Popular Cows(强连通分量缩点)

2018-01-13 20:55 381 查看
Popular Cows

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 36225 Accepted: 14759
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
USACO 2003 Fall

思路:最直接的想法是暴力搜索,首先,如果一个点能够到达所有点,则这头牛崇拜所有的牛,那么反过来(将所有路线反向,即崇拜变为被崇拜)之后,如果某个点能到达所有点,那个这头牛就被所有的牛崇拜(逆向思维),不过这样做的复杂度高达O(m*n),会超时。只得另辟蹊径了,首先来看有向无环图,其中有两类点非常特殊,一种是入度为0的点,一种是出度为0的点,如果某个有向无环图中只有一个出度为0点,那么所有的点都有路径到达这个点,而且有且仅有这个点(DAG(有向无环图的性质
无论图是否连通 可以自己画一下))。如果题目中这个图是有向无环图就好办了,可惜不是。。。那么是不是可以转化成有向无环图呢,关键在于如何去掉环路,每个最大的环路其实就是一个连通分量,在这个环里面所有奶牛都是互相崇拜的,不用管环内部的情况,把每个环看成一个点,重新构图,再寻找出度为0的点,,出度为0的个数一定大于等于1(当原图为连通图时,转化为1个点,个数最小为1),如果等于1,答案则是出度为0对应的连通分量的点的个数。(注意如果图中有孤立的点也会被考虑进去,即出度为0的个数大于1)。这里求强连通分量用的是tarjan算法。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
using namespace std;
#define N 10005
stack<int> sta;
vector<int> mp
;
int dfn
,low
,vis
,num
,degree
;
int n,m,cnt,id,ans;

void init(){
cnt=0;
id=0;
ans=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
memset(degree,0,sizeof(degree));
while(!sta.empty())
sta.pop();
for(int i=1;i<=n;i++)
mp[i].clear();
}

void tarjan(int x){
dfn[x]=low[x]=++id;
sta.push(x);
vis[x]=1;
for(int i=0;i<mp[x].size();i++){
int t=mp[x][i];
if(!dfn[t]) {
tarjan(t);
low[x]=min(low[x],low[t]);
}else if(vis[t]) low[x]=min(low[x],dfn[t]);
}

if(dfn[x]==low[x]){
int tp;
cnt++;
do{
tp=sta.top();
vis[tp]=0;
num[tp]=cnt;
sta.pop();
}while(tp!=x);
}
}

void slove(){
int sum=0,index;
for(int i=1;i<=n;i++){
for(int j=0;j<mp[i].size();j++){
if(num[i]!=num[mp[i][j]])
degree[num[i]]++;
}
}

for(int i=1;i<=cnt;i++){
if(!degree[i])
sum++,index=i;
}

if(sum>1) cout<<"0"<<endl;
else {
for(int i=1;i<=n;i++)
if(num[i]==index)
ans++;
cout<<ans<<endl;
}
}

int main(){
while(cin>>n>>m){
init();
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
mp[a].push_back(b);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
slove();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: