1. 程式人生 > >Papa的朋友圈(原POJ 2186)Tarjan

Papa的朋友圈(原POJ 2186)Tarjan

iostream idt urn pac ros stdio.h eight div fin

題目描述

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
輸出樣例:
1

說明

只有 3 號可以做網紅

【數據範圍】

10%的數據N<=20, M<=50

30%的數據N<=1000,M<=20000

70%的數據N<=5000,M<=50000

100%的數據N<=10000,M<=50000


雖然是道Tarjan裸題,但沒有學長指導確實自己做不出來

解析:

這道題我們用一個雙端隊列(vctor)來儲存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
*/

Papa的朋友圈(原POJ 2186)Tarjan