我要讲的实际上是下面这道题:html
对于n个数,一直它们间m对关系(即pi>pj),问至少还须要知道多少堆关系才能将它们排序。c++
问题理解起来很简单,相信有的读者一眼看去就知道是拓扑排序(我一开始也是这么认为的),那么我就仅仅附上拓扑排序的代码,由于我真正要讲的,并非拓扑排序法优化
#include<bits/stdc++.h> using namespace std; const int maxn=1000+15; int n,m,sum; int head[maxn],vis[maxn]; bitset<maxn> rel[maxn]; struct EDGE { int to;int next; }edge[maxn*20]; void add(int x,int y) { edge[++sum].next=head[x]; edge[sum].to=y; head[x]=sum; } void dfs(int x) { vis[x]=1; for (int i=head[x];i;i=edge[i].next) { if (!vis[edge[i].to]) dfs(edge[i].to); rel[x]|=rel[edge[i].to]; } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) rel[i][i]=true; for (int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); } for (int i=1;i<=n;i++) if (!vis[i]) dfs(i); int ans=0; for (int i=1;i<=n;i++) ans+=rel[i].count(); printf("%d",n*(n-1)/2-ans+n); return 0; }
之因此不讲,是由于我认为我还不能彻底的理解url
下面我来介绍一种更为简单的方法(floyd)spa
首先告诉你们这题的数据,n<=1000,那么正常状况下n^3的floyd确定是不行的了,有个操做叫作手动压位能下降复杂度,然而我不会。我会的方法并非手动的,而是利用STL库里的bitset进行优化.net
应该有很多的人不知道bitset是何物,我推荐一个我本身发现的一篇博客,但愿对你们有帮助bitset讲解code
利用已知关系,咱们获得了一张有向无环图,对于任两点i j,如果i可以到j,这对于一个j能到的点集,i都能到达点集中的任意一点(联通)。能够明确,若是给定的关系为0,排序以后咱们知道的关系就是n(n-1)/2(对于任意互异两点都知道关系),那么在floyd中咱们可以计算出已知关系的数量,从而最终肯定答案。下面我附上代码,注意当你看不懂输出的时候,代码下面我还会给予讲解(固然本身想一想也不错),上面拓扑排序的代码输出也是同样的。htm
#include<bits/stdc++.h> using namespace std; const int maxn=1000+15; int n,m; bitset<maxn>rel[maxn]; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) rel[i][i]=true; for (int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); rel[u][v]=true; } for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (rel[j][i]) rel[j]|=rel[i];//注意是判断rel[j][i],而不是rel[i][j](循环好像不能反过来写) int ans=0; for (int i=1;i<=n;i++) ans+=rel[i].count(); printf("%d",n*(n-1)/2-ans+n); return 0; }
输出讲解:注意一开始咱们对全部的i,都有bitset[i][i]=true,所以咱们最后要给已知的关系数ans减去n,以后再计算blog