Dominos<并查集求解>

来源:互联网 发布:素颜美女知乎 编辑:程序博客网 时间:2024/06/05 00:22

1900: Problem D: Dominos

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 97  Solved: 18
[Submit][Status][Web Board]

Description

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

13 21 22 3

Sample Output

1

HINT

Source


真的是错了几百遍才AC的题目,因为各种状况没有考虑到,最先看到这个题,立马就动手写了并查集,结果一提交就WA ,后来跟大佬们聊了会才发现,并查集他是一种双向存储,而题目中的意思只能是单向.

eg :

1

3 2

1 2

3 2

这种数据用并查集做出来的是1 但是实际上答案应该为2,考虑到这种情况,思路转了一下,又想起了当时AC 冠军代码的那道题,直接用一个数组把被推倒的骨牌存起来,然后没有被推倒过的骨牌就只能用手推啦 ,想到这我以为这就是个超级水超级水的水题了,然后一改代码提交,又是WA,好吧,再仔细找案例,就发现第二种做法有一种特殊情况:

eg :

1

3 3

1 2

2 1

1 3

这种如果用我刚刚说的方法来解,答案为0,而实际上应该为2,骨牌1和骨牌2成环,需要推一次(现实中两个牌应该不能成环的,这里不过举个例子),骨牌3单独一个需要推一次。


所以啊综上,我就直接把两种情况都一起考虑进来,直接输出两者的最大值,这样就把可能出错的情况都考虑进来了,然而又掉进了一个坑导致WA 。。。。


在设置数组来存储被推倒的骨牌是时,下标要跟骨牌的标号一致,(可能说的不太明白,直接上代码吧!)


#include<cstdio>#include<cstring>#include<cctype>#include<algorithm>#include<set>#include<cstring>#include<string>#include<iostream>#include<cmath>#include<map>using namespace std;int n;int pa[100005];int rank[100005];int find(int x){    if(x != pa[x])        pa[x] = find(pa[x]);    return pa[x];}void unions(int x, int y){    x = find(x);    y = find(y);    if(x == y)return ;//如果父亲一致,就不用合并    n--;//如果不一致,把总数减一,和我们之前做的宗教问题一样。    if(rank[x] > rank[y])    {        pa[y] = x;    }    else    {        pa[x] = y;        if(rank[x] == rank[y])            rank[y]++;    }}int v[100005];int main(){    int t;    scanf("%d",&t);    while(t--){            memset(v,0,sizeof(v));        int m;        scanf("%d %d",&n,&m);        int tt=n;   for(int i=0;i<=n;i++)//这个地方的初始化导致了多次WA,根据我自己的代码,v[i]表示的第i个骨牌被推倒,但是之前我的循环到n-1就结束了,导致了第n个没有被初始化    {        pa[i]=i;        rank[i]=0;    }    int a,b;        for(int i=0;i<m;i++){        scanf("%d %d",&a,&b);        unions(a,b);        v[b]=1;        }    int sum=0;    for(int i=1;i<=tt;i++)        if(!v[i]){        sum++;       // printf("i:%d\n",i);        }        printf("%d\n",max(sum,n));    }    return 0;}



原创粉丝点击