POJ-2186(強連通分量)

poj-2186

題意:每頭牛都想成爲牛羣中的紅人。給定N頭牛的牛羣和M個有序對(A, B)。(A, B)表示牛A認爲牛B是紅人。該關係具有傳遞性,所以如果牛A認爲牛B是紅人,牛B認爲牛C是紅人,那麼牛A也認爲牛C是紅人。不過,給定的有序對中可能包含(A, B)和(B, C),但不包含(A,C)。求被其他所有牛認爲是紅人的牛的總數。

比較暴力的思路:假如我們直接暴力就是我們直接建圖,然後再對每個點暴力就可以了,這樣也可以,但是就是時間的問題,肯定會超時的,既然時間上過不去,那麼我們不妨就試試我們剛剛學的強連通分量,

我們直接求出這個圖的拓撲序,想一下,這個點必須是所有的點都可以到達的點,只要我們找那些屬於最後一個分組的點有幾個就行了,然後在走一次dfs看看是不是所有的點都可以到達這個點,這樣我們就把這個題給做出來了,

下面給出AC代碼

#include<bits/stdc++.h>
using namespace std;
#define met(Q,QQ) memset(Q,QQ,sizeof(Q))
const int maxn=1e4+7;
vector<int> G[maxn];//存圖
vector<int> rG[maxn];//把邊反向後的圖
vector<int> vec;//後序遍歷順序的圖
bool vis[maxn];//訪問標記
int cmp[maxn];//所屬強聯通分量的拓撲序列
int n,m;

void add_edge(int from,int to)//存圖
{
    G[from].push_back(to);
    rG[to].push_back(from);
}

void dfs(int k)     //對圖進行dfs,並訪問到的點依次存入vec中,
{
    vis[k]=true;
    int kk=G[k].size();
    for(int i=0;i<kk;i++)
    {
        int kkk=G[k][i];
        if(!vis[kkk]) dfs(kkk);
    }
    vec.push_back(k);
}

void rdfs(int k,int cnt)//構建拓撲序
{
    vis[k]=true;
    cmp[k]=cnt;
    int kk=rG[k].size();
    for(int i=0;i<kk;i++)
    {
        int kkk=rG[k][i];
        if(!vis[kkk]) rdfs(kkk,cnt);
    }
}

int main()
{
    scanf("%d %d",&n,&m);
    int from,to;
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&from,&to);
        add_edge(from,to);
    }
    met(vis,0);
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]) dfs(i);
    }

    met(vis,0);
    int kk=vec.size();
    int cnt=0;
    for(int i=kk-1;i>=0;i--)
    {
        if(!vis[vec[i]])
        {
            cnt++;
            int qq=vec[i];
            rdfs(qq,cnt);
        }
    }

    int sum=0;
    int u=0;
    for(int i=1;i<=n;i++)
    {
        if(cmp[i]==cnt)
        {
            u=i;
            sum++;
        }
    }
    met(vis,0);
    rdfs(u,0);
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            sum=0;
            break;
        }
    }
    printf("%d\n",sum);



    return 0;
}





 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章