1. 程式人生 > >zcmu 1900: Problem D: Dominos(並查集)

zcmu 1900: Problem D: Dominos(並查集)

【題目】

Problem D: Dominos

Dominos are lots of fun. Children like to stand the tiles on their side in long lines. When one domino falls, it knocks down the next one, which knocks down the one after that, all the way down the line. However, sometimes a domino fails to knock the next one down. In that case, we have to knock it down by hand to get the dominos falling again.

Your task is to determine, given the layout of some domino tiles, the minimum number of dominos that must be knocked down by hand in order for all of the dominos to fall.

Input

The first line of input contains one integer specifying the number of test cases to follow. Each test case begins with a line containing two integers, each no larger than 100 000. The first integer n

 is the number of domino tiles and the second integer m is the number of lines to follow in the test case. The domino tiles are numbered from 1 to n. Each of the following lines contains two integers x and y indicating that if domino number x falls, it will cause domino number y to fall as well.

Output

For each test case, output a line containing one integer, the minimum number of dominos that must be knocked over by hand in order for all the dominos to fall.

Sample Input

1
3 2
1 2
2 3

Sample Output

1

【題意】

給定測試資料組數,每組給定牌數n和m對相連的牌(牌從1-n),給定x,y,x倒了下一張牌y也會倒,問需要推多少次使所有的牌都倒下。

【思路】

第一眼以為是普通並查集,寫好提交,wa了。       然後才發現,題目要求的是單向的,而並查集是雙向的qaq。

如:3 2

       1 2

       3 2

正確答案應該是2,而直接使用並查集的結果是1。因此我們需要考慮到沒有出現父節點的牌。又考慮到:

如:3 3

       1 2

       3 2

       3 3

這種情況。因此我們需要比較下並查集的集合數與沒有父節點的牌數,並輸出較大值。

【程式碼】

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define Pi acos(-1)
#define eps 1e-8
using namespace std;
typedef long long int ll;
#define mem(a) memset(a,0,sizeof(a))
int pre[100005],vis[100005];
int Find(int x) //尋找父節點
{
    return x==pre[x]?x:pre[x]=Find(pre[x]);
}
int join(int x,int y) //更新集合
{
    x=Find(x),y=Find(y);
    if(x!=y) pre[y]=x;
}
main()
{
    int t,n,m,x,y; scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m); mem(vis);
        for(int i=1;i<=n;i++) pre[i]=i; 
        while(m--)
        {
            scanf("%d%d",&x,&y);
            vis[y]=1; //記錄擁有父節點的牌
            join(x,y);
        }
        int c=0,cc=0;
        for(int i=1;i<=n;i++)
        {
            if(pre[i]==i) c++;
            if(!vis[i]) cc++;
        }
        printf("%d\n",max(c,cc));
    }
}