ZCMU—1900

1900: Problem D: Dominos

Time Limit: 1 Sec   Memory Limit: 128 MB
[ 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

1
3 2
1 2
2 3

Sample Output

1

【分析】

题意:给出多米诺骨牌的关系,x,y,如果x倒下,y也会倒下。
首先这道题不要以逻辑去考虑...因为会出现环啊或者是特殊不符合逻辑的情况...
一开始我以为是并查集,但是后来发现一件事,因为并查集的关系是双向的,但是这道题的关系其实是单向的,x倒了y会倒,但是y倒下x是不会倒下的....所以这道题就变成了强连通图,首先把所有环缩成一个点然后.....
但是我这里还是写了并查集,因为可以考虑一点,并查集会出现问题的情况只有一种,也就是1-2,3-2这种情况
这种情况是需要两次的,但是在并查集中它们会变成同一个集合,所以这里可以计算一下在读取时没有父亲的牌,然后并查集后的集合数,输出较大的那个。
但是其实我觉得...理解的话应该这样更容易,可以记录一下某个集合中的起点数,比如1-2,3-2这种情况,起点数就是2...不过这样写的话其实就是强联通图了hhh还是自己太菜...图论学的不是很好
【代码】
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int father[100100];
int vis[100100];
int n,m;
int find(int x)
{
    int xx=x;
    while (father[xx]!=xx) xx=father[xx];
    while (father[x]!=x)
    {
        int t=x;
        x=father[x];
        father[t]=xx;
    }
    return xx;
}
 
int main()
{
    int pp;scanf("%d",&pp);
    while (pp--)
    {
        scanf("%d%d",&n,&m);
        memset(vis,0,sizeof(vis));
        for (int i=0;i<=n;i++) father[i]=i;
        for (int i=0;i<m;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            vis[y]=1;
            int fx=find(x);
            int fy=find(y);
            if (fx!=fy) father[fy]=fx;
        }
        int ans=0;
        int aans=0;
        for (int i=1;i<=n;i++)
        {
            if (father[i]==i)
                ans++;
            if (!vis[i]) aans++;
        }
        printf("%d\n",max(aans,ans));
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值