我们存图的时候正着存一遍,倒着存一遍
正着DFS每个点的儿子,记录下来每个点有多少个子孙,反向亦如此
然后这样想:总点数n减去某个点的子孙和它本身,也就是剩下的点,如果小于晋升人数a
表示这个点一定晋升
然后反向的子孙数与本身的和如果大于晋升人数b
表示这个点一定不可能被晋升
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
const int N=5000+3;
const int INF=0x3f3f3f3f;
int a,b,n,m,u,v;
vector<int> G[N],g[N];
int z[N],d[N],vis[N];
int DFS(int id,int fa)
{
vis[id]=1;
int ans=0,val=0;
for(int i=0; i<G[id].size(); i++)
{
int node=G[id][i];
if(!vis[node])
ans=ans+1+DFS(node,fa);
}
return ans;
}
int dfs(int id,int fa)
{
vis[id]=1;
int ans=0,val=0;
for(int i=0; i<g[id].size(); i++)
{
int node=g[id][i];
if(!vis[node])
ans=ans+1+dfs(node,fa);
}
return ans;
}
int main()
{
scanf("%d%d%d%d",&a,&b,&n,&m);
for(int i=0; i<=n; i++) G[i].clear(),g[i].clear();
for(int i=1; i<=m; i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
g[v].push_back(u);
}
for(int i=0; i<n; i++)
{
memset(vis,0,sizeof(vis));
z[i]=DFS(i,i);
}
for(int i=0; i<n; i++)
{
memset(vis,0,sizeof(vis));
d[i]=dfs(i,i);
}
int ansa=0,ansb=0,ansbb=0;
for(int i=0;i<n;i++)
{
if(n-z[i]-1<a) ansa++;
if(n-z[i]-1<b) ansb++;
if(d[i]+1>b) ansbb++;
}
printf("%d\n%d\n%d\n",ansa,ansb,ansbb);
return 0;
}