Papa的朋友圈(原POJ 2186)Tarjan

题目描述

Papa朋友圈里的每一个人都梦想成为朋友圈里的网红。被所有人喜欢的人就是一个网红。Papa所有的朋友都是自恋狂,每个人总是喜欢自己的。人与人之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。Papa的朋友圈里共有N 个人,给定一些这些人之间的喜欢关系,请你算出有多少个人可以当网红。

 

输入格式: 
第一行:两个用空格分开的整数:N和M

第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B

输出格式: 
第一行:单独一个整数,表示朋友圈网红的数量

 

输入样例: 
3 3 
1 2 
2 1 
2 3 
输出样例: 

 

说明

只有 3 号可以做网红

【数据范围】

10%的数据N<=20, M<=50

30%的数据N<=1000,M<=20000

70%的数据N<=5000,M<=50000

100%的数据N<=10000,M<=50000


 虽然是道Tarjan裸题,但没有学长指导确实自己做不出来

解析:

这道题我们用一个动态数组(vector)来储存A 喜欢 B,相当于建一条 A 指向 B 的单向边

如图

本来的关系应是这样:

Tarjan后:

我们用一个 degree[] 储存出口,在两点不为强联通分量时才存在出口,因此我们把出口的degree保持为 0,其余则改变为true 

 

讲道理出口有且仅有一个

如果存在两个出口,那答案一定为0 —— 一定有两人互不喜欢,就不满足条件啦

 

MY:

#include<stdio.h>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int MX=10001;
int n,m,k,cnt,dfn[MX],low[MX],belong[MX],degree[MX];
bool vis[MX];
stack<int> stk;
vector<int> mp[MX];

void Tarjan(int x)
{
    dfn[x]=low[x]=++k;
    vis[x]=1;
    stk.push(x);
    for(int j=0;j<mp[x].size();++j)
    {
        int next=mp[x][j];
        if(!dfn[next])
        {
            Tarjan(next);
            low[x]=min(low[x],low[next]);
        }
        else {
            low[x]=min(low[x],dfn[next]);
        }
    }
    if(dfn[x] == low[x])
    {
        int top;
        cnt++;
        do
        {
            top=stk.top();
            stk.pop();
            belong[top]=cnt;
            
        }while(top!=x);
    }
    
}

void sol()
{
    int ans=0,sum=0,index;
    for(int i=1;i<=n;++i)
    {
        for(int j=0;j<mp[i].size();++j)
        {
            if(belong[i] != belong[mp[i][j]])
            degree[belong[i]]++;
        }
    }
    for(int i=1;i<=cnt;++i)
    {
        if(!degree[i]) 
        sum++,index=i;
    }
    if(sum>1) {
        printf("0");
    }
    else {
        for(int i=1;i<=n;++i)
        {
            if(belong[i] == index) {
                ans++;
            }
        }
        printf("%d",ans);
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        mp[a].push_back(b);
    }
    for(int i=1;i<=n;++i)
    {
        if(!dfn[i])
            Tarjan(i);
    }
    sol();
    return 0;
}

 

学长滴:

#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[N];
int dfn[N],low[N],vis[N],num[N],degree[N];
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 solve(){
    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);
        solve();
    }
}
/*
3 4
1 2
2 1
2 3
3 2
*/

 

posted @ 2018-08-04 17:56  qseer  阅读(171)  评论(0编辑  收藏  举报