题目传送门:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=701&page=show_problem&problem=5324
n个人升职,规定m组关系:x晋升y必须晋升。求最大排名不超过a,b和最小排名大于b的人数。
一看就是拓扑排序啊!
然而这题可能有很多个图,不一定联通,怎么办?
学习到了新的计算拓扑序的方法:dfs.
有多少个前驱节点,拓扑排序排名最小就为多少。
有多少个后继节点,拓扑排序排名最大就为总节点数减后继节点数。
#include <cstdio> #include <iostream> #include <string.h> #define mem0(a) memset(a,0,sizeof(a)) #define meminf(a) memset(a,0x3f,sizeof(a)) using namespace std; const int maxn=5005,maxk=20005; int head[maxn],headi[maxn]; bool visit[maxn]; int num,cnt,inum; struct Edge { int from,to,pre; }; Edge edge[maxk],edgei[maxk]; void addedge(int from,int to) { edge[num]=(Edge){from,to,head[from]}; head[from]=num++; edgei[inum]=(Edge){to,from,headi[to]}; headi[to]=inum++; } void dfs(int now) { cnt++; visit[now]=1; for (int i=head[now];i!=-1;i=edge[i].pre) { if (!visit[edge[i].to]) dfs(edge[i].to); } } void dfs2(int now) { cnt++; visit[now]=1; for (int i=headi[now];i!=-1;i=edgei[i].pre) { if (!visit[edgei[i].to]) dfs2(edgei[i].to); } } int main() { int a,b,n,m,i,j,x,y,ansa,ansb; scanf("%d%d%d%d",&a,&b,&n,&m); memset(head,-1,sizeof(head)); memset(headi,-1,sizeof(headi)); num=0; for (i=1;i<=m;i++) { scanf("%d%d",&x,&y); x++;y++; addedge(x,y); } ansa=ansb=0; for (i=1;i<=n;i++) { cnt=0; mem0(visit); dfs(i); cnt=n-cnt+1; if (cnt<=a) ansa++; if (cnt<=b) ansb++; } cout << ansa << endl; cout << ansb << endl; int ans=0; for (i=1;i<=n;i++) { cnt=0; mem0(visit); dfs2(i); if (cnt>b) ans++; } cout << ans << endl; return 0; }