# Cattle off Netcom known brother (tarjan + mind)

 

In times of war, A country sent many spies to other countries to collect intelligence. Because the secret spy needs its own identity, so only one-way links between them. Therefore, only one-way links to a spy part of a spy. At the same time, spies do not know who to contact with him yes.
HA is a spy who's the boss, but he can only linked to espionage section. HA now there is a command has told all spies. HA at least I want to know how many he can contact his spies to tell notification to all spies.

Enter a description:

有多个测试数据。
对于每个测试数据:
第一行为一个整数n,m(0<n,m<=500)代表间谍的数量和HA能通知到的间谍的数量(间谍的编号为1-n);
第二行为m个用空格隔开的整数xi,代表HA能通知到的间谍的编号;
第三行到第n+2行,每一行第一个整数ai(0<=ai<n)表示第i-2个间谍能单向联系到的间谍数。之后有ai个用空格隔开的整数,表示间谍i-2能单向联系到的间谍的编号。

Output Description:

输出一行,此行中有一个整数,代表HA至少需要联系的间谍数。如果HA不能通知到所有间谍,输出-1。

Example 1

Entry

copy

3 2
1 2
1 2
1 1
0

Export

 

-1

Example 2

lose

 

3 1
1
2 2 3
0
0

Export

 

1

Subject to the effect: Enter a directed graph, and gives m, indicating that you can and m personal contact, ask how many people you need to contact a minimum, to contact the owner?

Thinking: is not difficult to see that this is the key to a strong connectivity problem, this question is that the person is not able to contact you included all those who need to be contacted, and if not, then it can not contact the owner, direct output to -1 it is good. So people need to be contacted have what characteristic? Writing a lot of water problems I encountered problems tarjan first reaction degree and out of the receding point is, and this happened to this question also related to:

To this figure as an example, you can notify people if only 1 or 2, then it can not be notified to the owner, if you are 1, 2 can notice, the minimum number notification is 2. Easy to see that the degree is the point 0 is required to be notified after shrinking point, their sum is at least the number you want to notice, because the penetration of not by other people to notice the point 0, and this point it is quite clear.

The last person that you can be notified of storage, where I chose the map, you can inform people of the second are + 1, as are non-notification of 0 degrees in the last traversing the point of time 0 , if the value of the second point is not empty, then, sum ++, or directly outputs -1 like.

If you do not understand, you can check out my other blog, wrote last month in graph theory, tarjan also wrote a lot of problems, water problems but there were also difficult, desire to help you!

AC Code: 

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;

struct node
{
    int v, next;
}e[maxn];
int dfn[maxn], low[maxn], suo[maxn], t, x;
int head[maxn], in[maxn], n, m, cnt, tot, scnt;
bool vis[maxn];
stack <int> st;
map <int, int> mp;
void init() {
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(head, -1, sizeof(head));
    memset(suo, 0, sizeof(suo));
    memset(in, 0, sizeof(in));
    memset(vis, 0, sizeof(vis));
    cnt = tot = scnt = 0;
}
void add (int from, int to) {
    e[++cnt].v = to;
    e[cnt].next = head[from];
    head[from] = cnt;
}
void tarjan(int x) {
    dfn[x] = low[x] = ++tot;
    vis[x] = 1;
    st.push(x);
    for (int i = head[x]; i != -1; i = e[i].next) {
        if (!dfn[e[i].v]) {
            tarjan (e[i].v);
            low[x] = min (low[x], low[e[i].v]);
        }
        else if (vis[e[i].v]) low[x] = min (low[x], dfn[e[i].v]);
    }
    if (dfn[x] == low[x]) {
        scnt++;
        int k;
        do {
            k = st.top();
            st.pop();
            suo[k] = scnt;
            vis[k] = 0;
        }
        while (k != x);
    }
}

int main()
{
    while (cin >> n >> m) {
        init();
        for (int i = 0; i < m; i++) {
            cin >> t;
            mp[t]++;
        }
        for (int i = 1; i <= n; i++) {
            cin >> t;
            while (t--) {
                cin >> x;
                add (i, x);
            }
        }
        for (int i = 1; i <= n; i++)  {
            if (!dfn[i]) tarjan(i);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = head[i]; j != -1; j = e[j].next) {
                int u = suo[i];
                int v = suo[e[j].v];
                if (u != v) in[v]++; //对缩点后的点进行入度更新
            }
        }
        int flag = 1, sum = 0;
        for (int i = 1; i <= scnt; i++) {
            if (!in[i]) {  //入度为0, 需要被通知
                int ans = 0; 
                for (auto it : mp) { // C++11以上可以使用的遍历器
                    if (suo[it.first] == i) {  second值由i, 表示可以通知到
                        ans = 1;
                        break;
                    }
                }
                if (!ans) {flag = 0; break;}
                else sum++;
            }
        }
        if (flag) cout << sum << endl;
        else cout << -1 << endl;
        mp.clear();   //注意map的清空, 否则会出错
    }
    return 0;
}

 

 

Guess you like

Origin blog.csdn.net/weixin_43851525/article/details/91871638