题解 CF277A 【Learning Languages】

题目传送门
来一发dfs的题解。

和其他题解中讲得一样,将每个语言、每个人都看作一个节点,一个人掌握一门语言就可以表示为将这个人代表的节点与这门语言代表的节点连一条边,只需将所有人都联通即可。

然后分一下类:

  1. 如果全是不会语言的人,那么显然需要连总人数条边(每个人都学同一门语言)。
  2. 如果有会语言的人,那么只需要连表示人的节点的总连通块数减一条边(将人分成不会语言的和会语言的,不会语言的同上,会语言的只需将它们连成一棵树即可,所以加起来是表示人的节点的总连通块数减一条)。

然后只需要用dfs求出表示人的节点的总连通块数,再根据上述分类操作即可

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,i,j,x,y,s;
vector<int>k[201];//邻接表存图,1-100号节点表示人,101-200号节点表示语言
bool b[201],bb;//b数组代表该节点是否被遍历过,bb代表是否有会语言的人
void dfs(int x)
{
    b[x]=1;//将当前节点标为已遍历
    int i;
    for(i=0;i<k[x].size();i++)if(!b[k[x][i]])dfs(k[x][i]);//遍历与当前节点相连的其他未遍历的节点
}
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&x);
        while(x--)
        {
            scanf("%d",&y);
            k[i].push_back(100+y);//连边
            k[100+y].push_back(i);//连边
        }
    }
    for(i=1;i<=n;i++)
    {
        if(!b[i]){if(k[i].size()>=1)bb=1;s++;dfs(i);}//如果当前节点还没被遍历过,就将连通块数加一,在遍历该节点
    }
    if(bb)s--;//如果有会语言的人,就将答案减一
    printf("%d",s);
}

猜你喜欢

转载自www.cnblogs.com/pzc2004/p/11600851.html
今日推荐