这道题题意就是给你一个图然后输出那些通过该点可到带图中任意位置的点。
分析:要找到一些点,这些点的性质是通过这个点可以到达图中任意位置这就意味着这个点是连接了一个连通分量,那么在考虑这道题时就要往连通分量这方面考虑了,因为这个联通分量可能是一个大的连通分量,也可能是几个连通分量通过几个边连在一起,那么这道题就有了思路,先用tarjan算法求连通分量并且保存每个联通分量的点,然后再按照边的起点和终点查看是否在一个联通分量,如果不在,那么用这个边把这两个联通分量连在一起,并把其中一个标记,意味着起点的联通分量里的任意点可以到达终点联通分量的点,以此类推,最后没有被标记的连通分量就是我们要找的点,如果联通分量有多个点那么取排序后的第一个;
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 20;
int head[maxn];
int dfn[maxn];
int low[maxn];
bool vis[maxn];
int sc[maxn];
vector<int>p[maxn];
int tag[maxn];
stack<int>iron;
int cnt = 0, ans = 0;
int n, m;
struct Edge
{
int from, to, next;
}edge[maxn];
void ini()
{
memset(tag, 0, sizeof(tag));
memset(vis, false, sizeof(vis));
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(sc, 0, sizeof(sc));
cnt = 0, ans = 0;
}
void add(int u, int v)
{
edge[cnt].from = u;
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void dfs(int x)
{
low[x] = dfn[x] = ++cnt;
vis[x] = 1;
iron.push(x);
for (int i = head[x]; ~i; i = edge[i].next)
{
int j = edge[i].to;
if (!dfn[j])
{
dfs(j);
low[x] = min(low[x], low[j]);
}
else if (vis[j])
{
low[x] = min(low[x], low[j]);
}
}
if (low[x] == dfn[x])
{
++ans;
while (!iron.empty())
{
int t = iron.top();
vis[t] = 0;
p[ans].push_back(t);
sc[t] = ans;
iron.pop();
if (t == x)
break;
}
}
}
void tarjan()
{
for (int i = 1; i <= n; i++)
if (!dfn[i])
dfs(i);
}
int main()
{
scanf("%d %d", &n, &m);
ini();
for (int i = 0; i < m; i++)
{
int u, v;
scanf("%d %d", &u, &v);
add(u, v);
}
cnt = 0, ans = 0;
tarjan();
for (int i = 0; i < m; i++)
{
if (sc[edge[i].from] != sc[edge[i].to])
{
tag[sc[edge[i].to]] = 1;
}
}
for (int i = 1; i <= ans; i++)
sort(p[i].begin(), p[i].end());
vector<int>daan;
for (int i = 1; i <= ans; i++)
if ( !tag[ i ] )
daan.push_back(p[i][0]);
sort(daan.begin(), daan.end());
printf("%d\n", daan.size());
for (int i = 0; i < daan.size(); i++)
printf("%d ", daan[i]);
printf("\n");
system("pause");
return 0;
}