给定一张N个点M条边的有向无环图,分别统计从每个点出发能够到达的点的数量。
输入格式
第一行两个整数N,M,接下来M行每行两个整数x,y,表示从x到y的一条有向边。
输出格式
输出共N行,表示每个点能够到达的点的数量。
数据范围
1≤N,M≤30000
输入样例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
输出样例:
1
6
3
3
2
1
1
1
1
1
这个题需要先了解一下bitset,可以参考下面这篇博客。
参考博客:https://blog.csdn.net/qll125596718/article/details/6901935
我们需要得到Size[x]
那么我们就先需要得到Size[y] (x与y是有连接的)。
那么Size[x] = Size[y1] U Size[y2] ……
这个并集,是对Size[y1]能到达的结点 U Size[y2]能到达的结点。
也就是说如果有一个结点y1 和y2都能到达,那么对于x来说就只要求一次,所以是求并集。而并不是盲目的把y1能到达的结点个数+y2能到达的结点个数。
对于求并集来说,我们可以用二进制来表示。这就需要用到bitset了。
同时,我们求x,是需要求出y的。那么可以想一下,拓扑序序列一定是x在前y在后,所以我们可以用拓扑序,从后往前求。
#include"stdio.h"
#include"string.h"
#include"vector"
#include"map"
#include"queue"
#include"iostream"
#include"algorithm"
#include <bitset>
using std::bitset;
using namespace std;
typedef pair<int,int> PII;
int N,M;
vector<int> Q[30010];
int vis[30010],Size[30010],in[30010];
int num[30010],to[30010],top;
map<PII,int> P;
bitset<30010>f[30010];
void topo()
{
queue<int> Qu;
for(int i = 1; i <= N; i ++)
if(in[i] == 0)
Qu.push(i);
while(!Qu.empty())
{
int v = Qu.front();
to[++ top] = v;
Qu.pop();
for(int i = 0; i < Q[v].size(); i ++)
{
int u = Q[v][i];
in[u] --;
if(in[u] == 0)
Qu.push(u);
}
}
}
int main()
{
scanf("%d%d",&N,&M);
for(int i = 1; i <= M; i ++)
{
int x,y;scanf("%d%d",&x,&y);
if(P[{x,y}] == 0)
{
Q[x].push_back(y);
in[y] ++;
}
P[{x,y}] = 1;
}
topo();
for(int i = top; i >= 1; i --)
{
int u = to[i];
f[u].set(u);
for(int j = 0; j < Q[u].size(); j ++)
f[u] |= f[Q[u][j]];
Size[u] = f[u].count();
}
for(int i = 1; i <= N; i ++)
printf("%d\n",Size[i]);
}
其实也可以不用拓扑排序,直接dfs。每次都更新一下f值就可以了
#include"stdio.h"
#include"string.h"
#include"vector"
#include"map"
#include"queue"
#include"iostream"
#include"algorithm"
#include <bitset>
using std::bitset;
using namespace std;
typedef pair<int,int> PII;
int N,M;
vector<int> Q[30010];
int vis[30010],Size[30010],in[30010];
int num[30010],to[30010],top;
map<PII,int> P;
bitset<30010>f[30010];
void dfs(int x)
{
f[x].set(x);
for(int i = 0; i < Q[x].size(); i ++)
{
int v = Q[x][i];
if(vis[v] == 0)
{
vis[v] = 1;
dfs(v);
}
f[x] |= f[v];
}
}
int main()
{
scanf("%d%d",&N,&M);
for(int i = 1; i <= M; i ++)
{
int x,y;scanf("%d%d",&x,&y);
if(P[{x,y}] == 0)
{
Q[x].push_back(y);
in[y] ++;
}
P[{x,y}] = 1;
}
for(int i = 1; i <= N; i ++)
{
if(vis[i] == 0)
{
vis[i] = 1;
dfs(i);
}
}
for(int i = 1; i <= N; i ++)
printf("%d\n",f[i].count());
}