1. 程式人生 > >2018年全國多校演算法寒假訓練營練習比賽(第四場) E-通知小弟

2018年全國多校演算法寒假訓練營練習比賽(第四場) E-通知小弟

連結:https://www.nowcoder.com/acm/contest/76/E

來源:牛客網

題目描述

        在戰爭時期,A國派出了許多間諜到其他國家去收集情報。因為間諜需要隱祕自己的身份,所以他們之間只是單向聯絡。所以,某個間諜只能單向聯絡到一部分的間諜。同時,間諜也不知道跟他聯絡的是誰。
HA是間諜們的老大,但他也只能聯絡到部分的間諜。HA現在有一項命令有告訴所有的間諜。HA想要知道他至少要告訴多少個他能聯絡上的間諜才能通知到所有的間諜。

輸入描述:

有多個測試資料。
對於每個測試資料:
第一行為一個整數n,m(0<n,m<=500)代表間諜的數量和HA能通知到的間諜的數量(間諜的編號為1-n);
第二行為m個用空格隔開的整數xi,代表HA能通知到的間諜的編號;
第三行到第n+2行,每一行第一個整數ai(0<=ai<n)表示第i-2個間諜能單向聯絡到的間諜數。之後有ai個用空格隔開的整數,表示間諜i-2能單向聯絡到的間諜的編號。

輸出描述:

輸出一行,此行中有一個整數,代表HA至少需要聯絡的間諜數。如果HA不能通知到所有間諜,輸出-1。

這題為有向圖,有主次,所以可以使用並查集實現,每一次傳遞訊息就是一次路徑壓縮,只用找出那些孤立點再與ha比較就行

#include<bits/stdc++.h>
using namespace std;
int f[501],n,m,l;
int can[501];
int findset(int x)
{
    return x==f[x]?x:findset(f[x]);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=1;i<=m;i++)
    {
        cin>>l;
        can[l]=1;
    }
    for(int i=1;i<=n;i++)
    {
        int a,k;
        cin>>a;
        int aa=findset(i),bb;
        while(a--)
        {
            cin>>k;
            bb=findset(k);
            if(aa!=bb)
                f[k]=i;
        }
    }
    int flag=0,ans=0;
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i)
        {
            if(!can[i])
            {
                flag=1;
                break;
            }
            ans++;
        }
    }
    if(flag==0)
    cout<<ans<<endl;
    else
    cout<<-1<<endl;
    return 0;
}