PTA 1118 Birds in Forest (25 分)【並查集】

題目

一幅畫裏面的鳥爲同一棵樹上的,問有多少棵樹和多少隻鳥,以及對於兩隻鳥判斷是否在同一個樹上~

輸入第一行爲N,接下來有N行

這N行中,第一個是這幅畫(這棵樹)裏面的鳥的數量K,接下來是這K個鳥的編號。輸出有多少棵樹,多少隻鳥。

接着,輸入Q,表示詢問的個數。

接下來的Q行,有兩個鳥的編號,問你這兩個鳥是不是在同一幅畫(一棵樹)中。

分析

躺屍很多天。。。

並查集選擇使用了遞歸寫法。


int ffind(int a)
{
    if( a != pre[a])
    {
        pre[a] = ffind(pre[a]);
    }
    return pre[a];
}

但是要注意這種寫法中,

  if(exist[i]) //cout << i << " " << pre[i] << endl;
   {
         int root = ffind(i);
          cnt[root] ++;
         //cout << i << " " << root << endl;
   }

這兩個地方cout的結果是不同的。遞歸寫法需要再一次壓縮路徑。

代碼


const int maxn = 1e4 + 10;
int pre[maxn];
int exist[maxn];
int cnt[maxn];

int ffind(int a)
{
    if( a != pre[a])
    {
        pre[a] = ffind(pre[a]);
    }
    return pre[a];
}

int main()
{
    for(int i = 0 ; i < maxn ; i ++)
        pre[i] = i;
    int N ; cin >> N;
    for(int i = 0 ; i < N ; i ++)
    {
        int K ; cin >> K;
        int st ; cin >> st; exist[st] = 1;
        for(int i = 0 ; i < K - 1 ; i ++)
        {
            int ed ; cin >> ed; exist[ed] = 1;
            int prest = ffind(st);
            int preed = ffind(ed);

            if(prest != preed)
            {
                pre[prest] = preed;
            }
        }
    }

    for(int i = 1 ; i < maxn ; i ++)
    {
            if(exist[i]) //cout << i << " " << pre[i] << endl;
            {
                int root = ffind(i);
                cnt[root] ++;
                //cout << i << " " << root << endl;
            }
    }
    int numtree = 0 , numbird = 0;
    for(int i = 1 ; i < maxn ; i ++)
    {
       if(exist[i] && cnt[i])
       {
           numtree ++;
           numbird += cnt[i];
       }
    }
    cout << numtree << " " << numbird << endl;
    int Q ; cin >> Q;
    for(int i = 0 ; i < Q ; i ++)
    {
        int a , b;
        cin >> a >> b;
        if(ffind(a) != ffind(b))
            cout << "No" << endl;
        else cout << "Yes" << endl;
    }

}

 

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