目录
思路1:强连通缩点,与https://ac.nowcoder.com/acm/problem/15707类似。
思路3:贪心+DFS,入度为零的点一定是需要联系,再遍历其他点,最后判断是否都能联系上。
思路4:并查集求父节点。如果遍历了m个点后每个点都能到达,那么每个父节点也都能到达,可以同理为从父节点向下遍历,那么父节点的个数就是答案。
链接:https://ac.nowcoder.com/acm/problem/15120
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
在战争时期,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。
示例1
输入
3 2
1 2
1 2
1 1
0
输出
-1
示例2
输入
3 1
1
2 2 3
0
0
输出
1
思路1:强连通缩点,与https://ac.nowcoder.com/acm/problem/15707类似。
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int N = 1000;
int n,m;
int vis[N];
int low[N];
int dfn[N];
stack<int>s;
vector<int>v[N];
int num[N];
int ans;
int tim;
int sign[N];
int cnt;
int tem[N];
int in[N];
vector<int> rul;
void targan(int x)
{
low[x] = dfn[x] = ++tim;
s.push(x);
vis[x] = 1;
for(int i=0; i<v[x].size(); i++)
{
int y = v[x][i];
if(!dfn[y])
{
targan(y);
low[x] = min(low[x], low[y]);
}
else if(vis[y]) low[x] = min(low[x], dfn[y]);
}
if(dfn[x] == low[x])
{
int a;
cnt++;
do
{
a = s.top();
s.pop();
vis[a] = 0;
sign[a] = 1;
tem[a] = cnt;
}while(a != x);
}
}
int main()
{
cin>>n>>m;
for(int i=0; i<m; i++) cin>>num[i];
for(int i=1; i<=n; i++)
{
int a;
cin>>a;
for(int j=0; j<a; j++)
{
int b;
cin>>b;
v[i].push_back(b);
}
}
for(int i=0; i<m; i++)
{
if(!sign[num[i]])
{
rul.push_back(num[i]);
targan(num[i]);
}
}
for(int i=1; i<=n; i++)
{
if(!sign[i])
{
puts("-1");
return 0;
}
}
for(int i=1; i<=n; i++)
{
for(int j=0; j<v[i].size(); j++)
{
int u = v[i][j];
if(tem[i] != tem[u]) in[u]++;
}
}
for(int i=0; i<rul.size(); i++)
{
if(!in[rul[i]]) ans++;
}
cout<<ans;
return 0;
}
思路2:DFS加去重。
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int N = 1000;
int n,m;
vector<int> v[N];
int num[N];
int ans;
int rul[N];
int vis[N];
void dfs(int x,int y)
{
vis[x] = 1;
for(int i=0; i<v[x].size(); i++)
{
int a = v[x][i];
if(!vis[a]) dfs(a,y);
else if(a != y && rul[a])
{
rul[a] = 1;
ans--;
}
}
}
int main()
{
cin>>n>>m;
for(int i=0; i<m; i++) cin>>num[i];
for(int i=1; i<=n; i++)
{
int a;
cin>>a;
for(int j=0; j<a; j++)
{
int b;
cin>>b;
v[i].push_back(b);
}
}
for(int i=0; i<m; i++)
{
int a = num[i];
if(!vis[a])
{
rul[a] = 1;
ans++;
dfs(a,a);
}
}
for(int i=1; i<=n; i++)
if(!vis[i])
{
puts("-1");
return 0;
}
cout<<ans;
return 0;
}
思路3:贪心+DFS,入度为零的点一定是需要联系,再遍历其他点,最后判断是否都能联系上。
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int N = 1000;
int n,m;
vector<int> v[N];
int num[N];
int ans;
vector<int> rul;
int vis[N];
int in[N];
void dfs(int x)
{
vis[x] = 1;
for(int i=0; i<v[x].size(); i++)
{
int a = v[x][i];
if(!vis[a]) dfs(a);
}
}
int main()
{
cin>>n>>m;
for(int i=0; i<m; i++) cin>>num[i];
for(int i=1; i<=n; i++)
{
int a;
cin>>a;
for(int j=0; j<a; j++)
{
int b;
cin>>b;
v[i].push_back(b);
in[b]++;
}
}
for(int i=1; i<=m; i++)
{
if(!in[i]) rul.push_back(i);
}
for(int i=0; i<rul.size(); i++)
{
for(int j=0; j<m; j++)
{
if(rul[i] == num[j] && !vis[rul[i]])
{
ans++;
dfs(rul[i]);
}
}
}
for(int i=0; i<m; i++)
{
if(!vis[num[i]])
{
ans++;
dfs(num[i]);
}
}
int flag = 1;
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
flag = 0;
break;
}
}
if(flag) cout<<ans;
else
{
puts("-1");
}
return 0;
}
思路4:并查集求父节点。如果遍历了m个点后每个点都能到达,那么每个父节点也都能到达,可以同理为从父节点向下遍历,那么父节点的个数就是答案。
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int N = 1000;
int n,m;
vector<int> v[N];
int num[N];
int ans;
int vis[N];
int pre[N];
int findpre(int x)
{
return pre[x] == x ? x : (pre[x] = findpre(pre[x]));
}
void dfs(int x)
{
vis[x] = 1;
for(int i=0; i<v[x].size(); i++)
{
int a = v[x][i];
if(!vis[a]) dfs(a);
}
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++) pre[i] = i;
for(int i=0; i<m; i++) cin>>num[i];
for(int i=1; i<=n; i++)
{
int a;
cin>>a;
for(int j=0; j<a; j++)
{
int b;
cin>>b;
v[i].push_back(b);
int x = findpre(i);
int y = findpre(b);
pre[y] = x;
}
}
for(int i=0; i<m; i++)
{
if(!vis[num[i]]) dfs(num[i]);
}
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
puts("-1");
return 0;
}
}
for(int i=1; i<=n; i++)
{
if(i == pre[i]) ans++;
}
cout<<ans;
return 0;
}