zoukankan      html  css  js  c++  java
  • 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
    */
    从0到1很难,但从1到100很容易
  • 相关阅读:
    Windows Server 2012 R2 里面如何安装Net Framework 3.5
    虚拟机网络驱动(共享文件夹)不见了的解决方案-适用于win7~win10 and Windows Server 2008~Windows Server 2012R2
    在计算机 . 上没有找到服务 WAS
    免费获取WP之类的开发者权限或免费使用Azure 2015-10-19
    颠覆你的认知,带你领略史上最为齐全的微软黑科技之旅
    【技巧】只利用 Visual Stdio 自带的工具这么找父类?
    网站定位之---根据IP获得区域
    06.移动先行之谁主沉浮----我的代码我来写(Xaml的优势)
    05.移动先行之谁主沉浮----小应用的美化
    04.移动先行之谁主沉浮----XAML的探索
  • 原文地址:https://www.cnblogs.com/qseer/p/9389354.html
Copyright © 2011-2022 走看看