靜態傳遞閉包

我要講的實際上是下面這道題: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

相關文章
相關標籤/搜索