树与图的遍历
习题:可达性统计
思路
题目涉及到了bitset,状态压缩,可以看下这个 bitset 用法函数,状态压缩,练习题-CSDN博客
这里用了两种方法,如下:
-
运用记忆化,不断深搜所能达的点,并
进行|运算用set存放子节点,函数返回bitset类型
-
运用无后继–拓扑排序,因为子节点影响父节点,所以倒着来
出度为0,推入q
父节点|=子节点
代码
记忆化搜索+dfs+dp
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
const int N=3e4+10;
bool vis[N];//标记访问过的,实现记忆化
bitset<N> dp[N];//存储能遍历到该点的状态
set<int> sons[N];
bitset<N> dfs(int u)
{
if(vis[u]) return dp[u];
vis[u]=true;
dp[u].set(u);//u处置为1
for(auto &it:sons[u])
dp[u] |=dfs(it);//dfs里是小括号
return dp[u];
}
signed main()
{
IOS
int n,m,u,v;
cin>>n>>m;
while(m--)
{
cin>>u>>v;
sons[u].insert(v);
}
for(int i=1;i<=n;i++)
cout<<dfs(i).count()<<'\n';
}
拓扑排序+bfs
/*
* Project: 搜索,拓扑,状态压缩
* File Created: 7.27 2024
* Author: feishi
* Problem:Acwing 164. 可达性统计
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
queue <int> q;
const int N=3e4+10;
vector<int> ind[N];//存入度点
bitset<N> dp[N];
int chu[N];//记录出度数量,因为求得的是可达数量,倒序
signed main()
{
IOS
int n,m,u,v;
cin>>n>>m;
while(m--)
{
cin>>u>>v;
ind[v].push_back(u);
chu[u]++;
}
for(int i=1;i<=n;i++)
{
if(chu[i]==0)
{
q.push(i);
dp[i].set(i);
}
}
while(!q.empty())
{
int io=q.front();
q.pop();
for(auto &it:ind[io])
{
chu[it]--;
dp[it]|=dp[io];//io|他的出度
if(chu[it]==0)
{
dp[it].set(it);
q.push(it);
}
}
}
for(int i=1;i<=n;i++)
cout<<dp[i].count()<<'\n';
}