一.题目链接:
可达性统计
二.题目大意:
给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
三.分析:
第一想法是暴搜。。。。(我是不是没救了)
T是肯定的了。。。
对于每个点 x,他所能到达的点的个数 == y 能到达点的个数 + 1,其中存在 x 到 y 的有向边.
那么,我们可以先拓扑排序,得到拓扑序列,之后倒序遍历,统计个数即可.
统计时,可用 bitset 统计,按位与之后所得到的即为 x 点能到达的点.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;
const int M = (int)3e4;
const int mod = 99991;
const int inf = 0x3f3f3f3f;
int u, v, w;
int n, m, cnt = 1;
int head[M + 5];
struct node
{
int u, v, nx;
}Edge[M + 5];
int in[M + 5];
vector <int> path;
bitset <M + 5> bt[M + 5];
void add()
{
scanf("%d %d", &u, &v);
Edge[cnt].u = u;
Edge[cnt].v = v;
Edge[cnt].nx = head[u];
head[u] = cnt++;
in[v]++;
}
void topo()
{
queue <int> q;
for(int i = 1; i <= n; ++i)
{
if(!in[i])
q.push(i);
}
while(!q.empty())
{
u = q.front();
q.pop();
path.push_back(u);
for(int i = head[u]; i; i = Edge[i].nx)
{
v = Edge[i].v;
if(--in[v] == 0)
q.push(v);
}
}
}
int main()
{
scanf("%d %d", &n, &m);
while((m--) > 0)
add();
topo();
for(int i = path.size() - 1; i >= 0; --i)
{
u = path[i];
bt[u][u] = 1;
for(int j = head[u]; j; j = Edge[j].nx)
{
v = Edge[j].v;
bt[u] |= bt[v];
}
}
for(int i = 1; i <= n; ++i)
printf("%d\n", bt[i].count());
return 0;
}